From 7d1bfa3164a0e33b351f4c0496c42e5c15c5a16a Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 19 Jun 2023 19:11:33 +0300 Subject: [PATCH 01/51] added new message type handling for efento --- .../efento/CoapEfentoTransportResource.java | 331 +++++++++++++++++- .../efento/adaptor/EfentoCoapAdaptor.java | 14 +- .../coap/src/main/proto/proto_config.proto | 312 +++++++++++++++++ .../src/main/proto/proto_device_info.proto | 197 +++++++++++ .../coap/src/main/proto/proto_rule.proto | 267 ++++++++++++++ 5 files changed, 1107 insertions(+), 14 deletions(-) create mode 100644 common/transport/coap/src/main/proto/proto_config.proto create mode 100644 common/transport/coap/src/main/proto/proto_device_info.proto create mode 100644 common/transport/coap/src/main/proto/proto_rule.proto diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index 93061d522a..e2e08a669a 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -21,7 +21,6 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.Request; -import org.eclipse.californium.core.coap.Response; import org.eclipse.californium.core.network.Exchange; import org.eclipse.californium.core.server.resources.CoapExchange; import org.eclipse.californium.core.server.resources.Resource; @@ -34,6 +33,8 @@ import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeCon import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.auth.SessionInfoCreator; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.coap.ConfigProtos; +import org.thingsboard.server.gen.transport.coap.DeviceInfoProtos; import org.thingsboard.server.gen.transport.coap.MeasurementTypeProtos; import org.thingsboard.server.gen.transport.coap.MeasurementsProtos; import org.thingsboard.server.transport.coap.AbstractCoapTransportResource; @@ -43,12 +44,16 @@ import org.thingsboard.server.transport.coap.callback.CoapEfentoCallback; import org.thingsboard.server.transport.coap.efento.utils.CoapEfentoUtils; import java.nio.ByteBuffer; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static org.thingsboard.server.transport.coap.CoapTransportService.CONFIGURATION; import static org.thingsboard.server.transport.coap.CoapTransportService.CURRENT_TIMESTAMP; @@ -94,14 +99,13 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { String requestType = uriPath.get(1); switch (requestType) { case MEASUREMENTS: - processMeasurementsRequest(exchange, request); + processMeasurementsRequest(exchange); break; case DEVICE_INFO: + processDeviceInfoRequest(exchange); + break; case CONFIGURATION: - //We respond only to confirmed requests in order to reduce battery consumption for Efento devices. - if (exchange.advanced().getRequest().isConfirmable()) { - exchange.respond(new Response(CoAP.ResponseCode.CREATED)); - } + processConfigurationRequest(exchange); break; default: exchange.respond(CoAP.ResponseCode.BAD_REQUEST); @@ -109,8 +113,8 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { } } - private void processMeasurementsRequest(CoapExchange exchange, Request request) { - byte[] bytes = request.getPayload(); + private void processMeasurementsRequest(CoapExchange exchange) { + byte[] bytes = exchange.advanced().getRequest().getPayload(); try { MeasurementsProtos.ProtoMeasurements protoMeasurements = MeasurementsProtos.ProtoMeasurements.parseFrom(bytes); log.trace("Successfully parsed Efento ProtoMeasurements: [{}]", protoMeasurements.getCloudToken()); @@ -121,7 +125,7 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); try { validateEfentoTransportConfiguration(deviceProfile); - List efentoMeasurements = getEfentoMeasurements(protoMeasurements, sessionId); + List efentoMeasurements = getEfentoMeasurements(protoMeasurements, sessionId); transportService.process(sessionInfo, transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, efentoMeasurements), new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); @@ -137,6 +141,63 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { } } + private void processDeviceInfoRequest(CoapExchange exchange) { + byte[] bytes = exchange.advanced().getRequest().getPayload(); + try { + DeviceInfoProtos.ProtoDeviceInfo protoDeviceInfo = DeviceInfoProtos.ProtoDeviceInfo.parseFrom(bytes); + String token = protoDeviceInfo.getCloudToken(); + log.trace("Successfully parsed Efento ProtoDeviceInfo: [{}]", token); + transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(), + new CoapDeviceAuthCallback(exchange, (msg, deviceProfile) -> { + TransportProtos.SessionInfoProto sessionInfo = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()); + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); + try { + validateEfentoTransportConfiguration(deviceProfile); + EfentoTelemetry deviceInfo = getEfentoDeviceInfo(protoDeviceInfo); + transportService.process(sessionInfo, + transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, List.of(deviceInfo)), + new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); + reportSubscriptionInfo(sessionInfo, false, false); + } catch (AdaptorException e) { + log.error("[{}] Failed to decode Efento ProtoDeviceInfo: ", sessionId, e); + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } + })); + } catch (Exception e) { + log.error("Failed to decode Efento ProtoDeviceInfo: ", e); + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); + } + } + + private void processConfigurationRequest(CoapExchange exchange) { + byte[] bytes = exchange.advanced().getRequest().getPayload(); + try { + + ConfigProtos.ProtoConfig protoConfig = ConfigProtos.ProtoConfig.parseFrom(bytes); + String token = protoConfig.getCloudToken(); + log.trace("Successfully parsed Efento ProtoConfig: [{}]", token); + transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(), + new CoapDeviceAuthCallback(exchange, (msg, deviceProfile) -> { + TransportProtos.SessionInfoProto sessionInfo = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()); + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); + try { + validateEfentoTransportConfiguration(deviceProfile); + JsonObject config = getEfentoConfiguration(protoConfig); + transportService.process(sessionInfo, + transportContext.getEfentoCoapAdaptor().convertToPostAttribute(sessionId, config), + new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); + reportSubscriptionInfo(sessionInfo, false, false); + } catch (AdaptorException e) { + log.error("[{}] Failed to decode Efento ProtoConfig: ", sessionId, e); + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } + })); + } catch (Exception e) { + log.error("Failed to decode Efento ProtoConfig: ", e); + exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); + } + } + @Override public Resource getChild(String name) { return this; @@ -155,7 +216,7 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { } } - private List getEfentoMeasurements(MeasurementsProtos.ProtoMeasurements protoMeasurements, UUID sessionId) { + private List getEfentoMeasurements(MeasurementsProtos.ProtoMeasurements protoMeasurements, UUID sessionId) { String serialNumber = CoapEfentoUtils.convertByteArrayToString(protoMeasurements.getSerialNum().toByteArray()); boolean batteryStatus = protoMeasurements.getBatteryStatus(); int measurementPeriodBase = protoMeasurements.getMeasurementPeriodBase(); @@ -261,9 +322,9 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { throw new IllegalStateException("[" + sessionId + "]: Failed to get Efento measurements, reason: channels list is empty!"); } if (!CollectionUtils.isEmpty(valuesMap)) { - List efentoMeasurements = new ArrayList<>(); + List efentoMeasurements = new ArrayList<>(); for (Long ts : valuesMap.keySet()) { - EfentoMeasurements measurement = new EfentoMeasurements(ts, valuesMap.get(ts)); + EfentoTelemetry measurement = new EfentoTelemetry(ts, valuesMap.get(ts)); efentoMeasurements.add(measurement); } return efentoMeasurements; @@ -272,9 +333,253 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { } } + private EfentoTelemetry getEfentoDeviceInfo(DeviceInfoProtos.ProtoDeviceInfo protoDeviceInfo) { + JsonObject values = new JsonObject(); + values.addProperty("sw_version", protoDeviceInfo.getSwVersion()); + values.addProperty("cloud_token", protoDeviceInfo.getCloudToken()); + + //memory statistics + values.addProperty("nv_storage_status", getStorageStatus(protoDeviceInfo.getMemoryStatistics(0))); + values.addProperty("timestamp_of_the_end_of_collecting_statistics", getDate(protoDeviceInfo.getMemoryStatistics(1))); + values.addProperty("capacity_of_memory_in_bytes", protoDeviceInfo.getMemoryStatistics(2)); + values.addProperty("used_space_in_bytes", protoDeviceInfo.getMemoryStatistics(3)); + values.addProperty("size_of_invalid_packets_in_bytes", protoDeviceInfo.getMemoryStatistics(4)); + values.addProperty("size_of_corrupted_packets_in_bytes", protoDeviceInfo.getMemoryStatistics(5)); + values.addProperty("number_of_valid_packets", protoDeviceInfo.getMemoryStatistics(6)); + values.addProperty("number_of_invalid_packets", protoDeviceInfo.getMemoryStatistics(7)); + values.addProperty("number_of_corrupted_packets", protoDeviceInfo.getMemoryStatistics(8)); + values.addProperty("number_of_all_samples_for_channel_1", protoDeviceInfo.getMemoryStatistics(9)); + values.addProperty("number_of_all_samples_for_channel_2", protoDeviceInfo.getMemoryStatistics(10)); + values.addProperty("number_of_all_samples_for_channel_3", protoDeviceInfo.getMemoryStatistics(11)); + values.addProperty("number_of_all_samples_for_channel_4", protoDeviceInfo.getMemoryStatistics(12)); + values.addProperty("number_of_all_samples_for_channel_5", protoDeviceInfo.getMemoryStatistics(13)); + values.addProperty("number_of_all_samples_for_channel_6", protoDeviceInfo.getMemoryStatistics(14)); + values.addProperty("timestamp_of_the_first_binary_measurement", getDate(protoDeviceInfo.getMemoryStatistics(15))); + values.addProperty("timestamp_of_the_last_binary_measurement", getDate(protoDeviceInfo.getMemoryStatistics(16))); + values.addProperty("timestamp_of_the_first_binary_measurement_sent", getDate(protoDeviceInfo.getMemoryStatistics(17))); + values.addProperty("timestamp_of_the_first_continuous_measurement", getDate(protoDeviceInfo.getMemoryStatistics(18))); + values.addProperty("timestamp_of_the_last_continuous_measurement", getDate(protoDeviceInfo.getMemoryStatistics(19))); + values.addProperty("timestamp_of_the_last_continuous_measurement_sent", getDate(protoDeviceInfo.getMemoryStatistics(20))); + values.addProperty("nvm_write_counter", protoDeviceInfo.getMemoryStatistics(21)); + + //modem info + values.addProperty("modem_types", protoDeviceInfo.getModem().getType().toString()); + values.addProperty("sc_EARNFCN_offset", protoDeviceInfo.getModem().getParameters(0)); + values.addProperty("sc_EARFCN", protoDeviceInfo.getModem().getParameters(1)); + values.addProperty("sc_PCI", protoDeviceInfo.getModem().getParameters(2)); + values.addProperty("sc_Cell_id", protoDeviceInfo.getModem().getParameters(3)); + values.addProperty("sc_RSRP", protoDeviceInfo.getModem().getParameters(4)); + values.addProperty("sc_RSRQ", protoDeviceInfo.getModem().getParameters(5)); + values.addProperty("sc_RSSI", protoDeviceInfo.getModem().getParameters(6)); + values.addProperty("sc_SINR", protoDeviceInfo.getModem().getParameters(7)); + values.addProperty("sc_Band", protoDeviceInfo.getModem().getParameters(8)); + values.addProperty("sc_TAC", protoDeviceInfo.getModem().getParameters(9)); + values.addProperty("sc_ECL", protoDeviceInfo.getModem().getParameters(10)); + values.addProperty("sc_TX_PWR", protoDeviceInfo.getModem().getParameters(11)); + values.addProperty("op_mode", protoDeviceInfo.getModem().getParameters(12)); + values.addProperty("nc_EARFCN", protoDeviceInfo.getModem().getParameters(13)); + values.addProperty("nc_EARNFCN_offset", protoDeviceInfo.getModem().getParameters(14)); + values.addProperty("nc_PCI", protoDeviceInfo.getModem().getParameters(15)); + values.addProperty("nc_RSRP", protoDeviceInfo.getModem().getParameters(16)); + values.addProperty("RLC_UL_BLER", protoDeviceInfo.getModem().getParameters(17)); + values.addProperty("RLC_DL_BLER", protoDeviceInfo.getModem().getParameters(18)); + values.addProperty("MAC_UL_BLER", protoDeviceInfo.getModem().getParameters(19)); + values.addProperty("MAC_DL_BLER", protoDeviceInfo.getModem().getParameters(20)); + values.addProperty("MAC_UL_TOTAL_BYTES", protoDeviceInfo.getModem().getParameters(21)); + values.addProperty("MAC_DL_TOTAL_BYTES", protoDeviceInfo.getModem().getParameters(22)); + values.addProperty("MAC_UL_total_HARQ_Tx", protoDeviceInfo.getModem().getParameters(23)); + values.addProperty("MAC_DL_total_HARQ_Tx", protoDeviceInfo.getModem().getParameters(24)); + values.addProperty("MAC_UL_HARQ_re_Tx", protoDeviceInfo.getModem().getParameters(25)); + values.addProperty("MAC_DL_HARQ_re_Tx", protoDeviceInfo.getModem().getParameters(26)); + values.addProperty("RLC_UL_tput", protoDeviceInfo.getModem().getParameters(27)); + values.addProperty("RLC_DL_tput", protoDeviceInfo.getModem().getParameters(28)); + values.addProperty("MAC_UL_tput", protoDeviceInfo.getModem().getParameters(29)); + values.addProperty("MAC_DL_tput", protoDeviceInfo.getModem().getParameters(30)); + values.addProperty("sleep_duration", protoDeviceInfo.getModem().getParameters(31)); + values.addProperty("rx_time", protoDeviceInfo.getModem().getParameters(32)); + values.addProperty("tx_time", protoDeviceInfo.getModem().getParameters(33)); + + //Runtime info + DeviceInfoProtos.ProtoRuntime runtimeInfo = protoDeviceInfo.getRuntimeInfo(); + values.addProperty("battery_reset_timestamp", getDate(runtimeInfo.getBatteryResetTimestamp())); + values.addProperty("max_mcu_temp", runtimeInfo.getMaxMcuTemperature()); + values.addProperty("mcu_temp", runtimeInfo.getMcuTemperature()); + values.addProperty("counter_of_confirmable_messages_attempts", runtimeInfo.getMessageCounters(0)); + values.addProperty("counter_of_non_confirmable_messages_attempts", runtimeInfo.getMessageCounters(1)); + values.addProperty("counter_of_succeeded_messages", runtimeInfo.getMessageCounters(2)); + values.addProperty("min_battery_mcu_temp", runtimeInfo.getMinBatteryMcuTemperature()); + values.addProperty("min_battery_voltage", runtimeInfo.getMinBatteryVoltage()); + values.addProperty("min_mcu_temp", runtimeInfo.getMinMcuTemperature()); + values.addProperty("runtime_errors", runtimeInfo.getRuntimeErrorsCount()); + values.addProperty("up_time", runtimeInfo.getUpTime()); + + return new EfentoTelemetry(System.currentTimeMillis(), values); + } + + private JsonObject getEfentoConfiguration(ConfigProtos.ProtoConfig config) { + JsonObject values = new JsonObject(); + + values.addProperty("hash", config.getHash()); + values.addProperty("serial", CoapEfentoUtils.convertByteArrayToString(config.getSerialNumber().toByteArray())); + values.addProperty("timestamp", getDate(config.getHashTimestamp())); + values.addProperty("current_time", getDate(config.getCurrentTime())); + values.addProperty("apn", getString(config.getApn(), "\u007F", "Automatic")); + values.addProperty("cloud_token", config.getCloudToken()); + values.addProperty("token_config", getTokenConfigString(config.getCloudTokenConfig())); + values.addProperty("data_server", config.getDataServerIp() + ":" + config.getDataServerPort() + + "/" + config.getDataEndpoint()); + values.addProperty("update_server", config.getUpdateServerIp() + " Coap port " + + config.getUpdateServerPortCoap() + " Udp port " + config.getUpdateServerPortUdp()); + values.addProperty("device_info_endpoint", config.getDeviceInfoEndpoint()); + values.addProperty("configuration_endpoint", config.getConfigurationEndpoint()); + values.addProperty("time_endpoint", config.getTimeEndpoint()); + values.addProperty("transfer_limit", getStringValue(config.getTransferLimit(), 65535, "Disable")); + values.addProperty("plmn_selection", getPlmnSelection(config.getPlmnSelection())); + values.addProperty("supervision_period", getStringValue(config.getSupervisionPeriod(), 0xFFFFFFFF, "Functionality disabled")); + values.addProperty("modem_bands_mask", config.getModemBandsMask()); + values.addProperty("ACK", getStringValue(config.getAckInterval(), 0xFFFFFFFF, "Always request ACK")); + values.addProperty("ble_tx_power_level", config.getBleTxPowerLevel()); + values.addProperty("channel_types", config.getChannelTypesList().stream().map(Enum::toString).collect(Collectors.joining(","))); + values.addProperty("rules", config.getRulesList().stream().map(protoRule -> protoRule.getCondition().toString()).collect(Collectors.joining(","))); + values.addProperty("calendars", config.getCalendarsList().stream().map(protoCalendar -> protoCalendar.getType().toString()).collect(Collectors.joining(","))); + values.addProperty("cellular_config_params", config.getCellularConfigParamsList().stream().map(String::valueOf).collect(Collectors.joining(","))); + values.addProperty("dns_server_ip", config.getDnsServerIpList().stream().map(Object::toString).collect(Collectors.joining(","))); + values.addProperty("dns_ttl_config", getDnsTtlConfigString(config.getDnsTtlConfig())); + values.addProperty("token_coap_option", getStringValue(config.getCloudTokenCoapOption(), 65000, "Cloud token sent in the payload")); + values.addProperty("payload_signature_CoAP_option", getStringValue(config.getPayloadSignatureCoapOption(), 65000, "No payload signature in CoAP option")); + values.addProperty("payload_split_info", getPayloadSplitInfo(config.getPayloadSplitInfo())); + values.addProperty("led_config", config.getLedConfigList().stream().map(Object::toString).collect(Collectors.joining(","))); + values.addProperty("network_troubleshooting", getNetworkTroubleShooting(config.getNetworkTroubleshooting())); + values.addProperty("encryption_key", getEncryptionKey(config.getEncryptionKey().toByteArray())); + values.addProperty("apn_username", getString(config.getApnUserName(),"\u007F", "Automatic")); + values.addProperty("apn_password", getString(config.getApnPassword(),"\u007F", "Automatic")); + + return values; + } + + private String getStorageStatus(int status) { + String storageStatusString; + switch (status) { + case 0: + storageStatusString = "No errors"; + break; + case 1: + storageStatusString = "Nv storage has some corrupted packet. Memory is read-only"; + break; + case 2: + storageStatusString = "Nv storage is corrupted. Memory is unavailable"; + break; + default: + storageStatusString = String.valueOf(status); + } + return storageStatusString; + } + + private String getTokenConfigString(int tokenConfig) { + String tokenConfigString; + switch (tokenConfig) { + case 1: + tokenConfigString = "Cloud_token field value"; + break; + case 2: + tokenConfigString = "IMEI of the cellular module"; + break; + case 255: + tokenConfigString = "Do not send cloud_token field"; + break; + default: + tokenConfigString = String.valueOf(tokenConfig); + } + return tokenConfigString; + } + + private static String getString(String string, String marginalValue, String marginalDescription) { + String formatedString; + if (string.equals(marginalValue)) { + formatedString = marginalDescription; + } else { + formatedString = string; + } + return formatedString; + } + + private static String getEncryptionKey(byte[] bytes) { + String keyString; + if (Arrays.equals(bytes, new byte[] {0x7F})) { + keyString = "Encryption key disabled"; + } else { + keyString = CoapEfentoUtils.convertByteArrayToString(bytes); + } + return keyString; + } + + private static String getNetworkTroubleShooting(int networkTroubleShooting) { + String networkTroubleShootingString; + if (networkTroubleShooting == 1) { + networkTroubleShootingString = "Network troubleshooting disabled"; + } else if (networkTroubleShooting == 2) { + networkTroubleShootingString = "Network troubleshooting enabled"; + } else { + networkTroubleShootingString = String.valueOf(networkTroubleShooting); + } + return networkTroubleShootingString; + } + + private static String getPayloadSplitInfo(int info) { + String infoString; + if (info < 0) { + infoString = "Payload has been split, expect another part of the payload in the next message. The absolute value indicates an index of the current message."; + } else if (info == 0) { + infoString = "Payload has not been splitted"; + } else { + infoString = "Last part of the split payload, the value indicates the total number of the messages sent"; + } + return infoString; + } + + private static String getStringValue(int option, int marginalValue, String marginalDescription) { + String optionString; + if (option == marginalValue) { + optionString = marginalDescription; + } else { + optionString = String.valueOf(option); + } + return optionString; + } + + private static String getDnsTtlConfigString(int config) { + String configString; + if (config == 864001) { + configString = "Accept TTL from the DNS server (additionally, the DNS request when communication has failed)"; + } else if (config == 864002) { + configString = "DNS request is only after communication failed"; + } else { + configString = String.valueOf(config); + } + return configString; + } + + private static String getPlmnSelection(int selection) { + String selectionString; + if (selection == 1000000 || selection == 0xFFFFFFFF) { + selectionString = "automatic selection"; + } else { + selectionString = String.valueOf(selection); + } + return selectionString; + } + + private static String getDate(long seconds) { + if (seconds == -1L || seconds == 4294967295L) { + return "Undefined"; + } + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss Z"); + return simpleDateFormat.format(new Date(TimeUnit.SECONDS.toMillis(seconds))); + } + @Data @AllArgsConstructor - public static class EfentoMeasurements { + public static class EfentoTelemetry { private long ts; private JsonObject values; diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java index a6b588139a..6dec0a7002 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.coap.efento.adaptor; import com.google.gson.Gson; +import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.adaptor.AdaptorException; @@ -32,7 +33,7 @@ public class EfentoCoapAdaptor { private static final Gson gson = new Gson(); - public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, List measurements) throws AdaptorException { + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, List measurements) throws AdaptorException { try { return JsonConverter.convertToTelemetryProto(gson.toJsonTree(measurements)); } catch (Exception ex) { @@ -40,4 +41,15 @@ public class EfentoCoapAdaptor { throw new AdaptorException(ex); } } + + public TransportProtos.PostAttributeMsg convertToPostAttribute(UUID sessionId, JsonObject deviceInfo) throws AdaptorException { + try { + return JsonConverter.convertToAttributesProto(deviceInfo); + } catch (Exception ex) { + log.warn("[{}] Failed to convert JsonObject to PostTelemetry request!", sessionId); + throw new AdaptorException(ex); + } + } + + } diff --git a/common/transport/coap/src/main/proto/proto_config.proto b/common/transport/coap/src/main/proto/proto_config.proto new file mode 100644 index 0000000000..5e0537a5d9 --- /dev/null +++ b/common/transport/coap/src/main/proto/proto_config.proto @@ -0,0 +1,312 @@ +/** + * Copyright © 2016-2023 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. + */ +syntax = "proto3"; + +import "proto_measurement_types.proto"; +import "proto_rule.proto"; + +option java_package = "org.thingsboard.server.gen.transport.coap"; +option java_outer_classname = "ConfigProtos"; + +/* Message containing optional channels control parameters */ +message ProtoChannelControl { + + /* Channel index */ + uint32 channel_index = 1; + + /* Control parameters. Maximal number equals 4. This field is channel specific: */ + /* IO_control channel: */ + /* - control_params[0]: */ + /* - Byte 0: On state configuration */ + /* 0x01 - Low */ + /* 0x02 - High */ + /* 0x03 - High-Z (disconnected) */ + /* - Byte 1: Off state configuration */ + /* 0x01 - Low */ + /* 0x02 - High */ + /* 0x03 - High-Z (disconnected) */ + /* - Byte 2: Power on channel state */ + /* 0x01 - On */ + /* 0x02 - Off */ + repeated uint32 control_params = 2; +} + +/* Message containing request data for accesing calibration parameters */ +message ProtoCalibrationParameters { + + /* Request details. Bitmask: */ + /* - calibration_request[0:2] - requested channel number. */ + uint32 calibration_request = 1; + + /* Assignment of a channel. */ + uint32 channel_assignment = 2; + + /* Table of calibration parameters. Max size = 8. */ + repeated int32 parameters = 3; +} + +/* Main message sent in the payload. Each field in this message is independent of the others - only parameters that should be */ +/* changed need to be sent in the payload. */ +/* If the value of a selected parameter shall not be changed, do not include it in the payload */ +message ProtoConfig { + + /* DEPRECATED - Used for backward compatibility with fw versions 5.x */ + /* repeated Threshold thresholds = 1; */ + + /* 'Measurement_period_base' and 'measurement_period_factor' define how often the measurements are taken. */ + /* Sensors of 'Continuous' type take measurement each Measurement_period_base * measurement_period_factor. */ + /* Sensors of 'Binary' type take measurement each Measurement_period_base. */ + /* For backward compatibility with versions 5.x in case of binary/mixed sensors, if the 'measurement_period_factor' is */ + /* not sent (equal to 0), then the default value '14' shall be used for period calculation. */ + /* For backward compatibility with versions 5.x in case of continues sensors, if the measurement_period_factor is */ + /* not sent (equal to 0), then the default value '1' shall be used for period calculation. */ + /* measurement period base in seconds */ + /* Range [1:65535] - minimum value can vary depends on installed sensors */ + uint32 measurement_period_base = 2; + + /* Measurement period factor */ + /* Range [1:65535] - minimum value can vary depends on installed sensors */ + uint32 measurement_period_factor = 26; + + /* Transmission interval in seconds. Range: [60:604800] */ + uint32 transmission_interval = 3; + + /* BLE turnoff time in seconds. Once receiving this setting, BLE will be switched off after the set number of seconds. */ + /* If BLE is already switched off, it will switch on for the set number of seconds and switch off afterwards. */ + /* Range [60:604800] and 0xFFFFFFFF */ + /* 0xFFFFFFFF - always on */ + uint32 ble_turnoff_time = 4; + + /* ACK interval in seconds */ + /* Range [180:2592000] and 0xFFFFFFFF */ + /* 0xFFFFFFFF - always request ACK */ + uint32 ack_interval = 5; + + /* Specifies, if the additional device info is requested. If true, sensor will send a message to endpoint '/i' with the */ + /* device info. This field is only sent by server */ + bool request_device_info = 6; + + /* Specifies, if software update is available. This field is only sent by server */ + bool request_fw_update = 7; + + /* Current time in seconds sine 1st of January 1970 (epoch time). */ + uint32 current_time = 8; + + /* NB-IoT transfer limit */ + /* Range: [1:65535] */ + /* 65535 - disable transfer limit function */ + uint32 transfer_limit = 9; + + /* NB-IoT transfer limit timer in seconds */ + /* Range: [1:65535] */ + /* 65535 - disable transfer limit function */ + uint32 transfer_limit_timer = 10; + + /* Data (measurements) server IP address */ + /* IP of the data server as string in form x.x.x.x. For example: 18.184.24.239 */ + string data_server_ip = 11; + + /* Data (measurements) server port */ + /* Range: [1:65535] */ + uint32 data_server_port = 12; + + /* Update server IP address */ + /* IP of data server as string in form x.x.x.x. For example: 18.184.24.239 */ + string update_server_ip = 13; + + /* Update server port for UDP transmission */ + /* Range: [1:65535] */ + uint32 update_server_port_udp = 14; + + /* Update server port for CoAP transmission */ + /* Range: [1:65535] */ + uint32 update_server_port_coap = 15; + + /* APN as string. Max length 49 */ + /* String with special character 0x7F (DEL) only indicates that automatic apn is turn on */ + string apn = 16; + + /* PLMN selection */ + /* Range: [100:999999] */ + /* 0xFFFFFFFF or 1000000 - automatic selection */ + uint32 plmn_selection = 17; + + /* Device will power off its cellular modem for requested number of seconds. Maximum number of seconds 604800 (7 days) */ + /* This field is only sent by server */ + uint32 disable_modem_request = 18; + + /* If set, the device will send its configuration to the endpoint '/c' as a confirmable message */ + /* This field is only sent by server */ + bool request_configuration = 19; + + /* Device's error codes. */ + /* This field is only sent by device */ + repeated uint32 errors = 20; + + /* Identifier of current configuration - Every change of the configuration results in change of the value of this field */ + /* This field is only sent by device */ + uint32 hash = 21; + + /* If true, the device will accept the configuration without functional testing (eg. network connection) */ + bool accept_without_testing = 22; + + /* Cloud token configuration: */ + /* - 1: cloud token set to the value of cloud_token field */ + /* - 2: cloud token set to IMEI of the cellular module */ + /* - 255: do not send cloud_token field */ + uint32 cloud_token_config = 23; + + /* Cloud token that should be sent with each measurement frame */ + string cloud_token = 24; + + /* Serial number of the device */ + /* This field is only sent by device */ + bytes serial_number = 25; + + /* Type of channel */ + /* This field is only sent by device */ + repeated MeasurementType channel_types = 27; + + /* Edge logic rules set on the device. Up to 12 rules are supported */ + repeated ProtoRule rules = 28; + + /* Supervision period */ + /* Range: [180:604800] */ + /* 0xFFFFFFFF - Functionality disabled */ + uint32 supervision_period = 29; + + /* If true, sensor's measurement memory will be erased */ + bool memory_reset_request = 30; + + /* Bytes 0-4 - Band selection mask. Mask = 1 << position */ + /* Band | 1 | 2 | 3 | 4 | 5 | 8 | 12 | 13 | 17 | 18 | 19 | 20 | 25 | 26 | 28 | 66 | 71 | 85 | */ + /* Position: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | */ + /* example: To enable band 3, 8 and 20 set to (1 << 2) + (1 << 5) + (1 << 11) = 2084 */ + uint32 modem_bands_mask = 31; + + /* Data endpoint (string - max length 16) */ + string data_endpoint = 32; + + /* Configuration endpoint (string - max length 16) */ + string configuration_endpoint = 33; + + /* Device info endpoint (string - max length 16) */ + string device_info_endpoint = 34; + + /* Time endpoint (string - max length 16) */ + string time_endpoint = 35; + + /* Bluetooth TX power level. Value is the index of the absolute value of TX power, that depends on the BLE module */ + /* Range: [1:4] */ + uint32 ble_tx_power_level = 36; + + /* Deprecated field */ + /* If true, the sensor's runtime errors will be cleared */ + bool request_runtime_errors_clear = 37; + + /* Timestamp when a new error code was reported */ + uint32 error_timestamp = 38; + + /* Timestamp when the new configuration was set */ + uint32 hash_timestamp = 39; + + /* Cloud token CoAP option ID: */ + /* - [1:64999] - CoAP option ID containing cloud token */ + /* - 65000 - cloud token sent in the payload */ + uint32 cloud_token_coap_option = 40; + + /* ECDSA payload signature CoAP option ID: */ + /* - [1:64999] - CoAP option ID containing ECDSA payload signature */ + /* - 65000 - no payload signature in CoAP option */ + uint32 payload_signature_coap_option = 41; + + /* DNS server IP address grouped in the array as four octets. Set 255.255.255.255 to use a network DNS server */ + /* Note: when setting less than four octets the remaining will be filled with zeros. */ + repeated uint32 dns_server_ip = 42; + + /* DNS TTL configuration: */ + /* - [1:864000] - custom TTL in seconds (additionally, the DNS request when communication has failed) */ + /* - 864001 - accept TTL from the DNS server (additionally, the DNS request when communication has failed) */ + /* - 864002 - DNS request is only after communication failed */ + uint32 dns_ttl_config = 43; + + /* Configuration payload split information. Information about dividing the payload into parts */ + /* values < 0 - payload has been split, expect another part of the payload in the next message. */ + /* The absolute value indicates an index of the current message. */ + /* value = 0 - payload has not been splitted */ + /* values > 0 - last part of the split payload, the value indicates the total number of the messages sent */ + sint32 payload_split_info = 44; + + /* Modem update request (string - max length 48) */ + /* This field is only sent by server */ + /* For BC66 module, this field is a DFOTA URL */ + string modem_update_request = 45; + + /* Cellular configuration parameters. */ + /* 1st item - Number of used cellular parameters */ + /* 2nd - 12th items - Cellular parameters */ + repeated uint32 cellular_config_params = 46; + + /* Calendar configuration. Up to 6 calendars are supported */ + repeated ProtoCalendar calendars = 47; + + /* Control parameters for channels. Maximal number of requests equals 6 */ + /* This field is only sent by server */ + repeated ProtoChannelControl channels_control_request = 48; + + /* Set/get calibration parameters for single channel. */ + ProtoCalibrationParameters calibration_parameters_request = 49; + + /* LED behaviour configuration: */ + /* Period of LEDs flashing (5-600 seconds in 5 seconds resolution): */ + /* - led_config[0] - green LED */ + /* - led_config[1] - red LED */ + /* Time from entering the normal state, after which the LED indication is turned off */ + /* (0-240 minutes in 1 minute resolution, or 255 for always turned on): */ + /* - led_config[2] - flashing red led on communication problem */ + /* - led_config[3] - flashing red led on a sensor problem */ + /* - led_config[4] - flashing red led on a low power */ + /* - led_config[5] - flashing green led on measurement */ + /* - led_config[6] - flashing green led on transmission */ + /* - led_config[7] - flashing green led to indicate sensor's proper operation */ + /* - led_config[8] - Blink duration (20-1000ms in 5 ms resolution) */ + repeated uint32 led_config = 50; + + /* Network troubleshooting configuration, if bluetooth is turned off and communication with the server is faulty, */ + /* bluetooth will be automatically turned on until the connection is stabilized */ + /* - 1: network troubleshooting disabled */ + /* - 2: network troubleshooting enabled */ + uint32 network_troubleshooting = 51; + + /* Reserved by gateway client */ + reserved 52, 53; + + /* Encryption key configuration. Sensor sends in this field two last bytes of SHA256 hash calculated from its current */ + /* encryption_key configuration. */ + /* Max length: 16 bytes. */ + /* 0x7F - encryption key disabled. */ + bytes encryption_key = 54; + + /* User name as string. Max length 31 */ + /* String with special character 0x7F (DEL) only indicates that automatic user name is turn on */ + /* User name can only be set to custom value if apn has been configured (is not automatic) */ + string apn_user_name = 55; + + /* Password as string. Max length 31 */ + /* String with special character 0x7F (DEL) only indicates that automatic password is turn on */ + /* Password can only be set to custom value if apn_user_name has been configured (is not automatic) */ + string apn_password = 56; +} \ No newline at end of file diff --git a/common/transport/coap/src/main/proto/proto_device_info.proto b/common/transport/coap/src/main/proto/proto_device_info.proto new file mode 100644 index 0000000000..27dc73c25b --- /dev/null +++ b/common/transport/coap/src/main/proto/proto_device_info.proto @@ -0,0 +1,197 @@ +/** + * Copyright © 2016-2023 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. + */ +syntax = "proto3"; + +option java_package = "org.thingsboard.server.gen.transport.coap"; +option java_outer_classname = "DeviceInfoProtos"; + +enum ModemType +{ + + /* Invalid value */ + MODEM_TYPE_UNSPECIFIED = 0; + + /* Quectel BC66 modem */ + MODEM_TYPE_BC66 = 1; + + /* Quectel BC66-NA modem */ + MODEM_TYPE_BC66NA = 2; +} + +message ProtoRuntime +{ + + /* Up-time in seconds (since reset) */ + uint32 up_time = 1; + + /* Message counters (since reset). There are 3 counters: */ + /* message_counters[0] - Counter of confirmable messages attempts */ + /* message_counters[1] - Counter of non-confirmable messages attempts */ + /* message_counters[2] - Counter of succeeded messages */ + repeated uint32 message_counters = 2; + + /* MCU temperature in Celsius */ + sint32 mcu_temperature = 3; + + /* Minimum battery voltage in mV */ + uint32 min_battery_voltage = 4; + + /* MCU temperature in Celsius, while the minimum battery voltage was reached */ + sint32 min_battery_mcu_temperature = 5; + + /* Battery reset timestamp (Unix timestamp) */ + uint32 battery_reset_timestamp = 6; + + /* Max MCU temperature in Celsius */ + sint32 max_mcu_temperature = 7; + + /* Min MCU temperature in Celsius */ + sint32 min_mcu_temperature = 8; + + /* Table of runtime errors. Max length: 20 */ + repeated uint32 runtime_errors = 9; +} + +message ProtoModem +{ + + ModemType type = 1; + + /* Parameters for BC66 modem: */ + /* parameters[0] - sc_EARFCN - Range: [0:262143]. Unknown value: -1 */ + /* parameters[1] - sc_EARNFCN_offset - Range: [0:4] mapped to [-2, -1, -0.5, 0, 1]. Unknown value: -1 */ + /* parameters[2] - sc_PCI - Range: [0:502]. Unknown value: -1 */ + /* parameters[3] - sc_Cell id - Range: [1:268435456]. Unknown value: 0 */ + /* parameters[4] - sc_RSRP - [dBm] - Range: [-140:-44]. Unknown value: 0 */ + /* parameters[5] - sc_RSRQ - [dB] - Range: [-20:-3]. Unknown value: 0 */ + /* parameters[6] - sc_RSSI - [dBm] - Range: [-110:-3] Unknown value: 0 */ + /* parameters[7] - sc_SINR - [dB] - Range: [-10:30]. Unknown value: 31 */ + /* parameters[8] - sc_Band - Range: [see module supported bands]. The current serving cell band. Unknown value: -1 */ + /* parameters[9] - sc_TAC - Range: [0:65536]. Unknown value: -1 */ + /* parameters[10] - sc_ECL - Range: [0:2]. Unknown value: -1 */ + /* parameters[11] - sc_TX_PWR - [0.1cBm] - Range [-440:230]. Unknown value: -1000 */ + /* parameters[12] - OP_MODE - Range: [0:3]. Unknown value: -1 */ + /* parameters[13] - nc_EARFCN - Range: [0:262143]. Unknown value: -1 */ + /* parameters[14] - nc_EARNFCN_offset - Range: [0:4] mapped to [-2, -1, -0.5, 0, 1]. Unknown value: -1 */ + /* parameters[15] - nc_PCI - Range: [0:502]. Unknown value: -1 */ + /* parameters[16] - nc_RSRP - [dBm] - Range: [-140:-44]. Unknown value: 0 */ + /* parameters[17] - RLC_UL_BLER - Range: [0:100]. Unknown value: -1 */ + /* parameters[18] - RLC_DL_BLER - Range: [0:100]. Unknown value: -1 */ + /* parameters[19] - MAC_UL_BLER - Range: [0:100]. Unknown value: -1 */ + /* parameters[20] - MAC_DL_BLER - Range: [0:100]. Unknown value: -1 */ + /* parameters[21] - MAC_UL_TOTAL_BYTES - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[22] - MAC_DL_TOTAL_BYTES - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[23] - MAC_UL_total_HARQ_Tx - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[24] - MAC_DL_total_HARQ_Tx - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[25] - MAC_UL_HARQ_re_Tx - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[26] - MAC_DL_HARQ_re_Tx - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[27] - RLC_UL_tput - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[28] - RLC_DL_tput - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[29] - MAC_UL_tput - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[30] - MAC_DL_tput - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[31] - sleep_duration - [0.1s] - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[32] - Rx_time - [0.1s] - Range: [0:2147483647]. Unknown value: -1 */ + /* parameters[33] - Tx_time - [0.1s] - Range: [0:2147483647]. Unknown value: -1 */ + repeated sint32 parameters = 2; +} + +message ProtoUpdateInfo +{ + + /* Timestamp of update (Unix timestamp) */ + uint32 timestamp = 1; + + /* Update status, possible values: */ + /* - 0x1 - No update yet */ + /* - 0x2 - No error */ + /* - 0x3 - UDP socekt error */ + /* - 0x4 - Hash error */ + /* - 0x5 - Missing packet error */ + /* - 0x6 - Invalid data error */ + /* - 0x7 - Sending timeout error */ + /* - 0x8 - No SW to update error */ + /* - 0x9 - Sending unexpected error */ + /* - 0x10 - Unexpected error */ + uint32 status = 2; +} + +message ProtoDeviceInfo +{ + + /* Serial number of device */ + bytes serial_num = 1; + + /* Deprecated field */ + reserved 2; + + /* Software version e.g ver 06.10 -> 0x060A -> 1546 */ + uint32 sw_version = 3; + + /* Deprecated fields */ + reserved 4,5,6,7,8,9,10,11,12; + + /* Structure with battery and temperature information */ + ProtoRuntime runtime_info = 13; + + /* Structure with modem specific runtime information */ + ProtoModem modem = 14; + + /* String up to 7 bytes long. Software commit id e.g. "e0e8556" */ + /* From version 06.07 the first two characters indicate the LTS version. */ + /* For example: the value "0bdd23f" means LTS version 11 and the beginning of the commit ID "dd23f" */ + string commit_id = 15; + + /* Optional string up to 36 bytes long. Can be set to any user define value or hold device's IMEI */ + string cloud_token = 16; + + /* Memory statistics: */ + /* memory_statistics[0] - Status of Nv storage: */ + /* - 0 - Nv storage hasn't errors */ + /* - 1 - Nv storage has some corrupted packet. Memory is read-only */ + /* - 2 - Nv storage is corrupted. Memory is unavailable */ + /* memory_statistics[1] - Timestamp of the end of collecting statistics. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[2] - Capacity of memory in bytes */ + /* memory_statistics[3] - Used space in bytes */ + /* memory_statistics[4] - Size of invalid (outdated) packets in bytes */ + /* memory_statistics[5] - Size of corrupted packets in bytes */ + /* memory_statistics[6] - Number of valid packets */ + /* memory_statistics[7] - Number of invalid (outdated) packets */ + /* memory_statistics[8] - Number of corrupted packets */ + /* memory_statistics[9] - Number of all samples for channel 1 (valid packets) */ + /* memory_statistics[10] - Number of all samples for channel 2 (valid packets) */ + /* memory_statistics[11] - Number of all samples for channel 3 (valid packets) */ + /* memory_statistics[12] - Number of all samples for channel 4 (valid packets) */ + /* memory_statistics[13] - Number of all samples for channel 5 (valid packets) */ + /* memory_statistics[14] - Number of all samples for channel 6 (valid packets) */ + /* memory_statistics[15] - Timestamp of the first binary measurement. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[16] - Timestamp of the last binary measurement. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[17] - Timestamp of the last binary measurement, that marked as sent. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[18] - Timestamp of the first continuous measurement. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[19] - Timestamp of the last continuous measurement. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[20] - Timestamp of the last continuous measurement, that marked as sent. */ + /* Value in seconds since UNIX EPOCH 01-01-1970. Undefined value: 4294967295 */ + /* memory_statistics[21] - NVM write counter */ + repeated uint32 memory_statistics = 17; + + /* Information about last sensor SW update */ + ProtoUpdateInfo last_update_info = 18; +} \ No newline at end of file diff --git a/common/transport/coap/src/main/proto/proto_rule.proto b/common/transport/coap/src/main/proto/proto_rule.proto new file mode 100644 index 0000000000..9a4a3cd0d1 --- /dev/null +++ b/common/transport/coap/src/main/proto/proto_rule.proto @@ -0,0 +1,267 @@ +/** + * Copyright © 2016-2023 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. + */ +syntax = "proto3"; + +option java_package = "org.thingsboard.server.gen.transport.coap"; +option java_outer_classname = "ProtoRuleProtos"; + +/* Encoding A: used to set absolute values in the Rules (e.g. upper and lower threshold values) */ +/* - TEMPERATURE - [°C] - Celsius degree. Resolution 0.1°C. Range [-273.2:4000.0]. */ +/* - HUMIDITY - [% RH] - Relative humidity. Resolution 1%. Range [0:100]. */ +/* - ATMOSPHERIC_PRESSURE - [hPa] - Hectopascal (1hPa = 100Pa). Resolution 0.1hPa. Range: [1.0:2000.0]. */ +/* - DIFERENTIAL_PRESSURE - [Pa] - Pascal. Resolution 1Pa. Range [-10000:10000] */ +/* - OK/ALARM - Not applicable */ +/* - IAQ - [IAQ] - IAQ index. Resolution 1IAQ. Range [0:500]. */ +/* - FLOODING - Not applicable */ +/* - PULSE_CNT - [NB] Number of pulses. Resolution 1 pulse. Range [0:8000000]. */ +/* - ELECTRICITY_METER - [W] - Watt; Resolution 1W. Range [0:8000000]. Average power consumption in period */ +/* - WATER_METER [l/min] - Liter per minute. Resolution 1l/min. Range [0:8000000]. Average water flow in period. */ +/* - SOIL_MOISTURE - [kPa] - Kilopascal (1kPa = 1000Pa); Resolution 1kPa. Range [-1000:0]. Soil moisture (tension). */ +/* - CO_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [0:1000000]. Carbon monoxide concentration. */ +/* - NO2_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [0:1000000]. Nitrogen dioxide concentration. */ +/* - H2S_GAS - [ppm] - Parts per million. Resolution 0.01ppm. Range [0.00:80000.00]. Hydrogen sulfide concentration. */ +/* - AMBIENT_LIGHT -[lx] - Lux. Resolution 0.1lx. Range [0.0:100000.0]. Illuminance. */ +/* - PM_1_0 - [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [0:1000]. */ +/* - PM_2_5 - [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [0:1000]. */ +/* - PM_10_0 - [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [0:1000]. */ +/* - NOISE_LEVEL - [dB] - Decibels. Resolution 0.1 dB. Range: [0.0:200.0]. Noise level. */ +/* - NH3_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [0:1000000]. Ammonia concentration. */ +/* - CH4_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [0:1000000]. Methane concentration. */ +/* - HIGH_PRESSURE - [kPa] - Kilopascal (1kPa = 1000Pa, 100kPa = 1bar). Resolution 1kPa. Range [0:200000]. Pressure. */ +/* - DISTANCE_MM - [mm] - Millimeter. Resolution 1mm. Range [0:100000]. Distance. */ +/* - WATER_METER_ACC_MINOR - [l] - Liter. Resolution 1l. Range [0:1000000]. Accumulative water meter (minor). */ +/* - WATER_METER_ACC_MAJOR - [hl] - Hectoliter. Resolution 1hl. Range [0:1000000]. Accumulative water meter (major). */ +/* - CO2_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [0:1000000]. Carbon dioxide concentration. */ +/* - HUMIDITY ACCURATE - [% RH] - Relative humidity. Resolution 0.1%. Range [0.0:100.0]. */ +/* - STATIC_IAQ - [sIAQ] - Static IAQ index. Resolution 1sIAQ. Range [0:10000]. */ +/* - CO2_EQUIVALENT - [ppm] - Parts per million. Resolution 1ppm. Range [0:1000000]. Carbon dioxide equivalent. */ +/* - BREATH_VOC - [ppm] - Parts per million. Resolution 1ppm. Range [0:100000]. Breath VOC estimate. */ +/* - PERCENTAGE - [%] - Percentage. Resolution 0.01%. Range [0.00:100.00]. */ +/* - PULSE_CNT_ACC_MINOR - [NB] - Number of pulses. Resolution 1 pulse. Range [0:1000000]. Accumulative pulse counter (minor). */ +/* - PULSE_CNT_ACC_MAJOR - [kNB] - Number of kilopulses. Resolution 1 kilopulse. Range [0:1000000]. */ +/* Accumulative pulse counter (major). */ +/* - ELEC_METER_ACC_MINOR - [Wh] - Watt-hour. Resolution 1Wh. Range [0:1000000]. Accumulative electricity meter (minor). */ +/* - ELEC_METER_ACC_MAJOR - [kWh] - Kilowatt-hour. Resolution 1kWh. Range [0:1000000]. Accumulative electricity meter (major). */ + +/* Encoding R: used to set relative values in the Rules (e.g. differential threshold and hysteresis) */ +/* - TEMPERATURE - [°C] - Celsius degree. Resolution 0.1°C. Range [0.1:4273.2]. */ +/* - HUMIDITY - [% RH] - Relative humidity. Resolution 1%. Range [1:100]. */ +/* - ATMOSPHERIC_PRESSURE - [hPa] - Hectopascal (1hPa = 100Pa). Resolution 0.1hPa. Range: [0.1:1999.0]. */ +/* - DIFERENTIAL_PRESSURE - [Pa] - Pascal. Resolution 1Pa. Range [1:20000] */ +/* - OK/ALARM - Not applicable */ +/* - VOC - [IAQ] - Iaq index. Resolution 1IAQ. Range [1:500]. */ +/* - FLOODING - Not applicable */ +/* - PULSE_CNT - [NB] Number of pulses. Resolution 1 pulse. Range [1:8000000]. */ +/* - ELECTRICITY_METER - [W] - Watt; Resolution 1W. Range [1:8000000]. Average power consumption in period */ +/* - WATER_METER [l/min] - Liter per minute. Resolution 1l/min. Range [1:8000000]. Average water flow in period. */ +/* - SOIL_MOISTURE - [kPa] - Kilopascal (1kPa = 1000Pa); Resolution 1kPa. Range [1:1000]. Soil moisture (tension). */ +/* - CO_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [1:1000000]. Carbon monoxide concentration. */ +/* - NO2_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [1:1000000]. Nitrogen dioxide concentration. */ +/* - H2S_GAS - [ppm] - Parts per million. Resolution 0.01ppm. Range [0.01:80000.00]. Hydrogen sulfide concentration. */ +/* - AMBIENT_LIGHT -[lx] - Lux. Resolution 0.1lx. Range [0.1:100000.0]. Illuminance. */ +/* - PM_1_0 - [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [1:1000]. */ +/* - PM_2_5 - [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [1:1000]. */ +/* - PM_10_0 - [µg/m^3] - Micro gram per cubic meter. Resolution 1µg/m^3 Range [1:1000]. */ +/* - NOISE_LEVEL - [dB] - Decibels. Resolution 0.1 dB. Range: [0.1:200.0]. Noise level. */ +/* - NH3_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [1:1000000]. Ammonia concentration. */ +/* - CH4_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [1:1000000]. Methane concentration. */ +/* - HIGH_PRESSURE - [kPa] - Kilopascal (1kPa = 1000Pa, 100kPa = 1bar). Resolution 1kPa. Range [1:200000]. Pressure. */ +/* - DISTANCE_MM - [mm] - Millimeter. Resolution 1mm. Range [1:100000]. Distance. */ +/* - WATER_METER_ACC_MINOR - [l] - Liter. Resolution 1l. Range [1:1000000]. Accumulative water meter (minor). */ +/* - WATER_METER_ACC_MAJOR - [hl] - Hectoliter. Resolution 1hl. Range [1:1000000]. Accumulative water meter (major). */ +/* - CO2_GAS - [ppm] - Parts per million. Resolution 1ppm. Range [1:1000000]. Carbon dioxide concentration. */ +/* - HUMIDITY ACCURATE - [% RH] - Relative humidity. Resolution 0.1%. Range [0.1:100.0]. */ +/* - STATIC_IAQ - [sIAQ] - Static IAQ index. Resolution 1sIAQ. Range [1:10000]. */ +/* - CO2_EQUIVALENT - [ppm] - Parts per million. Resolution 1ppm. Range [1:1000000]. Carbon dioxide equivalent. */ +/* - BREATH_VOC - [ppm] - Parts per million. Resolution 1ppm. Range [1:100000]. Breath VOC estimate. */ +/* - PERCENTAGE - [%] - Percentage. Resolution 0.01%. Range [0.01:100.00]. */ +/* - PULSE_CNT_ACC_MINOR - [NB] - Number of pulses. Resolution 1 pulse. Range [1:1000000]. Accumulative pulse counter (minor). */ +/* - PULSE_CNT_ACC_MAJOR - [kNB] - Number of kilopulses. Resolution 1 kilopulse. Range [1:1000000]. */ +/* Accumulative pulse counter (major). */ +/* - ELEC_METER_ACC_MINOR - [Wh] - Watt-hour. Resolution 1Wh. Range [1:1000000]. Accumulative electricity meter (minor). */ +/* - ELEC_METER_ACC_MAJOR - [kWh] - Kilowatt-hour. Resolution 1kWh. Range [1:1000000]. Accumulative electricity meter (major). */ + +/* Condition to be checked by the device. If the condition is true, an action is triggered */ +enum Condition { + + /* Invalid value */ + CONDITION_UNSPECIFIED = 0; + + /* Threshold function for given rule_id is disabled */ + CONDITION_DISABLED = 1; + + /* Upper threshold. Continuous sensors only. If the measurement (or average from a few measurements) is over the threshold, */ + /* an action is triggered. */ + /* parameter[0] - Threshold value in "Encoding A" format. Must match channel type */ + /* parameter[1] - Hysteresis value in "Encoding R" format. Must much channel type. Set to "0" to disable */ + /* parameter[2] - Triggering mode: */ + /* - 1 - moving average (a1=(n1+n2+n3)/3, a2=(n2+n3+n4)/3, etc.) */ + /* - 2 - window average (a1=(n1+n2+n3)/3, a2=(n4+n5+n6)/3, etc.) */ + /* - 3 - consecutive samples (number of consecutive samples above threshold) */ + /* parameter[3] - Number of measurements for trigger determination. E.g parameter[3] equals 3, average value from three */ + /* samples will be calculated and compared to the threshold value in average mode or the third consecutive */ + /* sample above threshold will trigger action in consecutive mode. Range: [1:10]. */ + /* parameter[4] - Type of measurement (as described in MeasurementType). */ + CONDITION_HIGH_THRESHOLD = 2; + + /* Lower threshold. Continuous sensors only. If the measurement (or average from a few measurements) is below the threshold, */ + /* an action is triggered. */ + /* parameter[0] - Threshold value in "Encoding A" format. Must match channel type */ + /* parameter[1] - Hysteresis value in "Encoding R" format. Must much channel type. Set to "0" to disable */ + /* parameter[2] - Triggering mode: */ + /* - 1 - moving average (a1=(n1+n2+n3)/3, a2=(n2+n3+n4)/3, etc.) */ + /* - 2 - window average (a1=(n1+n2+n3)/3, a2=(n4+n5+n6)/3, etc.) */ + /* - 3 - consecutive samples (number of consecutive samples above threshold) */ + /* parameter[3] - Number of measurements for trigger determination. E.g parameter[3] equals 3, average value from three */ + /* samples will be calculated and compared to the threshold value in average mode or the third consecutive */ + /* sample below threshold will trigger action in consecutive mode. Range: [1:10]. */ + /* parameter[4] - Type of measurement (as described in MeasurementType). */ + CONDITION_LOW_THRESHOLD = 3; + + /* Differential threshold. Continuous sensors only. If the absolute value of the difference between the last value sent to */ + /* the server and the measurement value (or average from a few measurements) is greater or equal to the value of */ + /* the threshold set, an action is triggered. */ + /* parameter[0] - Threshold value in "Encoding R" format. Must match channel type */ + /* parameter[1] - Triggering mode: */ + /* - 1 - moving average (a1=(n1+n2+n3)/3, a2=(n2+n3+n4)/3, etc.) */ + /* - 2 - window average (a1=(n1+n2+n3)/3, a2=(n4+n5+n6)/3, etc.) */ + /* - 3 - consecutive samples (number of consecutive samples above threshold) */ + /* parameter[2] - Number of measurements for trigger determination. E.g parameter[3] equals 3, average value from three */ + /* samples will be calculated and compared to the threshold value in average mode or the third consecutive */ + /* sample exceeding threshold will trigger action in consecutive mode. Range: [1:10]. */ + /* parameter[3] - Type of measurement (as described in MeasurementType). */ + CONDITION_DIFF_THRESHOLD = 4; + + /* Change of binary sensor's state. Binary sensors only. Each change of the binary's sensor state will trigger an action. */ + CONDITION_BINARY_CHANGE_STATE = 5; + + /* Logic operator. Used for combining multiple rules into more complex conditions. If the logic condition specified by */ + /* parameters (logic operator and selected rules) is met, an action is triggered. */ + /* parameter[0] - Logic operator (as described in LogicOperation). */ + /* parameter[1] - Rule selector (bit mask). Specifies which rules should be taken into account while determining */ + /* rules outcome. */ + /* parameter[2] - Rule negation (bit mask). Specifies which of chosen in parameter[1] rules should be negated */ + /* before determining rules outcome. */ + /* parameter[3] - Rule action delay [s]. Specifies time delay between the rule activation and rule action being triggered. */ + /* Range: [0:864000]. */ + /* parameter[4] - Rule return delay [s]. Specifies time delay between the rule deactivation and rule action being triggered. */ + /* Range: [0:864001]. Max parameter value disables action triggering on rule deactivation. */ + CONDITION_LOGIC_OPERATOR = 6; + + /* On measurement. Continous sensors only. The basic function is to trigger communication after measurement if at least 60s */ + /* have passed since the last one. Transmission may occur every x measurement. Optionally dependency on the other rule can */ + /* be configured, then, when all conditions are met, transmission is triggered. */ + /* parameter[0] - Send every n measurement. This parameter specifies every which measurement transmission will be triggered */ + /* if all other conditions are met. Range: [1:500]. If parameter[0] equals 1, transmission will occur after */ + /* every measurement. */ + /* parameter[1] - Optional. Rule selector (bit mask). Specifies which rule should be taken into account while determining */ + /* the measurement rule outcome. */ + /* parameter[2] - Optional. Rule negation (bit mask). Specifies which of chosen in parameter[1] rule should be negated */ + /* before determining the measurement rule outcome. */ + CONDITION_ON_MEASUREMENT = 7; +} + +/* Logic operators to be used for determining the outcome of rules with logic operator condition. */ +enum LogicOperator { + + /* Invalid use */ + LOGIC_OPERATOR_UNSPECIFIED = 0; + + /* Logic AND */ + LOGIC_OPERATOR_AND = 1; + + /* Logic OR */ + LOGIC_OPERATOR_OR = 2; +} + +/* Action to be triggered. Currently the only possible action is to trigger the transmission. */ +/* Other actions will be available in next SW releases. */ +enum Action { + + /* Invalid value */ + ACTION_UNSPECIFIED = 0; + + /* To trigger the transmission */ + ACTION_TRIGGER_TRANSMISSION = 1; + + /* To take no action. Possible for logic operator components */ + ACTION_NO_ACTION = 2; + + /* To trigger the transmission with ACK */ + ACTION_TRIGGER_TRANSMISSION_WITH_ACK = 3; +} + +/* Type of a rule calendars. */ +enum CalendarType { + + /* Invalid value */ + CALENDAR_TYPE_UNSPECIFIED = 0; + + /* Type for inactive calendars */ + CALENDAR_TYPE_DISABLED = 1; + + /* Week type. Enables selcted rules on specified days of the week in specified time periods. */ + /* parameter[0] - Week day mask. Bitmask of days when selected rules are enabled */ + /* - Bit 0 - Sunday */ + /* - Bit 1 - Monday */ + /* ... */ + /* - Bit 6 - Saturday */ + /* parameter[1] - 'From time' - point in time from which selected rules will be enabled (in minutes from midnight). */ + /* parameter[2] - 'To time' - point in time from which selected rules will be disabled (in minutes from midnight). */ + /* Note: if 'From time' is bigger than 'To time' there are two periods when rules are enabled - from 00:00 to 'To time' */ + /* and from 'From time' to 23:59. */ + /* parameter[3] - Timezone - desired timezone for date comparison. Encoded as number (N) of 15 minutes offsets */ + /* - example - if N = 4, then offset = 4 * 15min = 1h. I.e. timezone is UTC+1. */ + CALENDAR_TYPE_WEEK = 2; +} + +/* Rules calendars. Used for enabling/disabling rules based on date/time. */ +/* It is possible to configure up to 6 calendars. Each of them can affect any number of rules. */ +message ProtoCalendar { + + /* Bit mask of selected rules. Mask on bits [0:11] */ + /* - Bit 0 - Rule ID 0 */ + /* - Bit 1 - Rule ID 1 */ + /* ... */ + /* - Bit 11 - Rule ID 11 */ + uint32 rule_mask = 1; + + /* Calendars's parameters. Described in Type. */ + repeated sint32 parameters = 2; + + /* Calendar's type. Described in Type. */ + CalendarType type = 3; +} + +/* Rules used to define edge logic on the device. Rules are defined by conditions and actions: */ +/* If Condition is true, trigger Action. It is possible to configure up to 12 rules and assign them to different channels. */ +/* One rule can be assigned to any number of channels. For instance rule "If temperature is over 10 C, trigger the transmission"*/ +/* can be assigned to channels 1 and 2. No matter to how many channels a rule is assigned, it's still counted as one rule. */ +message ProtoRule { + + /* Channels to which the rule is assigned. One rule can be assigned to multiple channels as long as those are of the same type*/ + /* Bit mask on bits [0:5]. E.g. To assign the rule for channel 1: "000001", to assign rule to channels 2 and 4: "001010" */ + uint32 channel_mask = 1; + + /* Rule's condition (as described in Condition). */ + Condition condition = 2; + + /* Condition's parameters (as described in Condition). For binary sensors there are no parameters */ + repeated sint32 parameters = 3; + + /* Action to be triggered. */ + Action action = 4; +} \ No newline at end of file From ea19c4accef8ecdade503b488cb849db86da30d7 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Jun 2023 12:06:56 +0300 Subject: [PATCH 02/51] refactoring --- .../transport/coap/efento/CoapEfentoTransportResource.java | 4 +--- .../transport/coap/efento/adaptor/EfentoCoapAdaptor.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index e2e08a669a..97788bbc5d 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -184,7 +184,7 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { validateEfentoTransportConfiguration(deviceProfile); JsonObject config = getEfentoConfiguration(protoConfig); transportService.process(sessionInfo, - transportContext.getEfentoCoapAdaptor().convertToPostAttribute(sessionId, config), + transportContext.getEfentoCoapAdaptor().convertToPostAttributes(sessionId, config), new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); reportSubscriptionInfo(sessionInfo, false, false); } catch (AdaptorException e) { @@ -336,7 +336,6 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { private EfentoTelemetry getEfentoDeviceInfo(DeviceInfoProtos.ProtoDeviceInfo protoDeviceInfo) { JsonObject values = new JsonObject(); values.addProperty("sw_version", protoDeviceInfo.getSwVersion()); - values.addProperty("cloud_token", protoDeviceInfo.getCloudToken()); //memory statistics values.addProperty("nv_storage_status", getStorageStatus(protoDeviceInfo.getMemoryStatistics(0))); @@ -424,7 +423,6 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { values.addProperty("timestamp", getDate(config.getHashTimestamp())); values.addProperty("current_time", getDate(config.getCurrentTime())); values.addProperty("apn", getString(config.getApn(), "\u007F", "Automatic")); - values.addProperty("cloud_token", config.getCloudToken()); values.addProperty("token_config", getTokenConfigString(config.getCloudTokenConfig())); values.addProperty("data_server", config.getDataServerIp() + ":" + config.getDataServerPort() + "/" + config.getDataEndpoint()); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java index 6dec0a7002..fde2d69181 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java @@ -42,7 +42,7 @@ public class EfentoCoapAdaptor { } } - public TransportProtos.PostAttributeMsg convertToPostAttribute(UUID sessionId, JsonObject deviceInfo) throws AdaptorException { + public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, JsonObject deviceInfo) throws AdaptorException { try { return JsonConverter.convertToAttributesProto(deviceInfo); } catch (Exception ex) { From a46f2b0708a76c408761bce9cad11cbfedc7c64e Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 3 Jul 2023 13:17:56 +0300 Subject: [PATCH 03/51] refactoring --- .../efento/CoapEfentoTransportResource.java | 336 +++++------------- .../efento/adaptor/EfentoCoapAdaptor.java | 8 +- 2 files changed, 101 insertions(+), 243 deletions(-) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index 97788bbc5d..31a57fbaf5 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -15,10 +15,13 @@ */ package org.thingsboard.server.transport.coap.efento; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.protobuf.InvalidProtocolBufferException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.TriConsumer; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.Request; import org.eclipse.californium.core.network.Exchange; @@ -31,6 +34,7 @@ import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransp import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeConfiguration; import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.common.transport.adaptor.ProtoConverter; import org.thingsboard.server.common.transport.auth.SessionInfoCreator; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.coap.ConfigProtos; @@ -46,15 +50,15 @@ import org.thingsboard.server.transport.coap.efento.utils.CoapEfentoUtils; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; +import java.util.function.Consumer; +import static com.google.gson.JsonParser.parseString; import static org.thingsboard.server.transport.coap.CoapTransportService.CONFIGURATION; import static org.thingsboard.server.transport.coap.CoapTransportService.CURRENT_TIMESTAMP; import static org.thingsboard.server.transport.coap.CoapTransportService.DEVICE_INFO; @@ -118,23 +122,17 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { try { MeasurementsProtos.ProtoMeasurements protoMeasurements = MeasurementsProtos.ProtoMeasurements.parseFrom(bytes); log.trace("Successfully parsed Efento ProtoMeasurements: [{}]", protoMeasurements.getCloudToken()); - String token = protoMeasurements.getCloudToken(); - transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(), - new CoapDeviceAuthCallback(exchange, (msg, deviceProfile) -> { - TransportProtos.SessionInfoProto sessionInfo = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()); - UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - try { - validateEfentoTransportConfiguration(deviceProfile); - List efentoMeasurements = getEfentoMeasurements(protoMeasurements, sessionId); - transportService.process(sessionInfo, - transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, efentoMeasurements), - new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); - reportSubscriptionInfo(sessionInfo, false, false); - } catch (AdaptorException e) { - log.error("[{}] Failed to decode Efento ProtoMeasurements: ", sessionId, e); - exchange.respond(CoAP.ResponseCode.BAD_REQUEST); - } - })); + validateAndProcessEffentoMessage(protoMeasurements.getCloudToken(), exchange, (deviceProfile, sessionInfo, sessionId) -> { + try { + List measurements = getEfentoMeasurements(protoMeasurements, sessionId); + transportService.process(sessionInfo, + transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, measurements), + new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); + } catch (AdaptorException e) { + log.error("[{}] Failed to decode Efento ProtoMeasurements: ", sessionId, e); + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } + }); } catch (Exception e) { log.error("Failed to decode Efento ProtoMeasurements: ", e); exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); @@ -147,22 +145,17 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { DeviceInfoProtos.ProtoDeviceInfo protoDeviceInfo = DeviceInfoProtos.ProtoDeviceInfo.parseFrom(bytes); String token = protoDeviceInfo.getCloudToken(); log.trace("Successfully parsed Efento ProtoDeviceInfo: [{}]", token); - transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(), - new CoapDeviceAuthCallback(exchange, (msg, deviceProfile) -> { - TransportProtos.SessionInfoProto sessionInfo = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()); - UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - try { - validateEfentoTransportConfiguration(deviceProfile); - EfentoTelemetry deviceInfo = getEfentoDeviceInfo(protoDeviceInfo); - transportService.process(sessionInfo, - transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, List.of(deviceInfo)), - new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); - reportSubscriptionInfo(sessionInfo, false, false); - } catch (AdaptorException e) { - log.error("[{}] Failed to decode Efento ProtoDeviceInfo: ", sessionId, e); - exchange.respond(CoAP.ResponseCode.BAD_REQUEST); - } - })); + validateAndProcessEffentoMessage(token, exchange, (deviceProfile, sessionInfo, sessionId) -> { + try { + EfentoTelemetry deviceInfo = getEfentoDeviceInfo(protoDeviceInfo); + transportService.process(sessionInfo, + transportContext.getEfentoCoapAdaptor().convertToPostTelemetry(sessionId, List.of(deviceInfo)), + new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); + } catch (AdaptorException e) { + log.error("[{}] Failed to decode Efento ProtoDeviceInfo: ", sessionId, e); + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } + }); } catch (Exception e) { log.error("Failed to decode Efento ProtoDeviceInfo: ", e); exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); @@ -172,32 +165,44 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { private void processConfigurationRequest(CoapExchange exchange) { byte[] bytes = exchange.advanced().getRequest().getPayload(); try { - ConfigProtos.ProtoConfig protoConfig = ConfigProtos.ProtoConfig.parseFrom(bytes); String token = protoConfig.getCloudToken(); log.trace("Successfully parsed Efento ProtoConfig: [{}]", token); - transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(), - new CoapDeviceAuthCallback(exchange, (msg, deviceProfile) -> { - TransportProtos.SessionInfoProto sessionInfo = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()); - UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); - try { - validateEfentoTransportConfiguration(deviceProfile); - JsonObject config = getEfentoConfiguration(protoConfig); - transportService.process(sessionInfo, - transportContext.getEfentoCoapAdaptor().convertToPostAttributes(sessionId, config), - new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); - reportSubscriptionInfo(sessionInfo, false, false); - } catch (AdaptorException e) { - log.error("[{}] Failed to decode Efento ProtoConfig: ", sessionId, e); - exchange.respond(CoAP.ResponseCode.BAD_REQUEST); - } - })); + validateAndProcessEffentoMessage(token, exchange, (deviceProfile, sessionInfo, sessionId) -> { + try { + JsonElement configuration = getEfentoConfiguration(bytes); + transportService.process(sessionInfo, + transportContext.getEfentoCoapAdaptor().convertToPostAttributes(sessionId, configuration), + new CoapEfentoCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR)); + } catch (AdaptorException e) { + log.error("[{}] Failed to decode Efento ProtoConfig: ", sessionId, e); + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + }); } catch (Exception e) { log.error("Failed to decode Efento ProtoConfig: ", e); exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); } } + private void validateAndProcessEffentoMessage(String token, CoapExchange exchange, TriConsumer requestProcessor) { + transportService.process(DeviceTransportType.COAP, TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(token).build(), + new CoapDeviceAuthCallback(exchange, (msg, deviceProfile) -> { + TransportProtos.SessionInfoProto sessionInfo = SessionInfoCreator.create(msg, transportContext, UUID.randomUUID()); + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); + try { + validateEfentoTransportConfiguration(deviceProfile); + requestProcessor.accept(deviceProfile, sessionInfo, sessionId); + reportSubscriptionInfo(sessionInfo, false, false); + } catch (AdaptorException e) { + log.error("[{}] Failed to decode Efento request: ", sessionId, e); + exchange.respond(CoAP.ResponseCode.BAD_REQUEST); + } + })); + } + @Override public Resource getChild(String name) { return this; @@ -338,7 +343,7 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { values.addProperty("sw_version", protoDeviceInfo.getSwVersion()); //memory statistics - values.addProperty("nv_storage_status", getStorageStatus(protoDeviceInfo.getMemoryStatistics(0))); + values.addProperty("nv_storage_status", protoDeviceInfo.getMemoryStatistics(0)); values.addProperty("timestamp_of_the_end_of_collecting_statistics", getDate(protoDeviceInfo.getMemoryStatistics(1))); values.addProperty("capacity_of_memory_in_bytes", protoDeviceInfo.getMemoryStatistics(2)); values.addProperty("used_space_in_bytes", protoDeviceInfo.getMemoryStatistics(3)); @@ -362,41 +367,42 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { values.addProperty("nvm_write_counter", protoDeviceInfo.getMemoryStatistics(21)); //modem info - values.addProperty("modem_types", protoDeviceInfo.getModem().getType().toString()); - values.addProperty("sc_EARNFCN_offset", protoDeviceInfo.getModem().getParameters(0)); - values.addProperty("sc_EARFCN", protoDeviceInfo.getModem().getParameters(1)); - values.addProperty("sc_PCI", protoDeviceInfo.getModem().getParameters(2)); - values.addProperty("sc_Cell_id", protoDeviceInfo.getModem().getParameters(3)); - values.addProperty("sc_RSRP", protoDeviceInfo.getModem().getParameters(4)); - values.addProperty("sc_RSRQ", protoDeviceInfo.getModem().getParameters(5)); - values.addProperty("sc_RSSI", protoDeviceInfo.getModem().getParameters(6)); - values.addProperty("sc_SINR", protoDeviceInfo.getModem().getParameters(7)); - values.addProperty("sc_Band", protoDeviceInfo.getModem().getParameters(8)); - values.addProperty("sc_TAC", protoDeviceInfo.getModem().getParameters(9)); - values.addProperty("sc_ECL", protoDeviceInfo.getModem().getParameters(10)); - values.addProperty("sc_TX_PWR", protoDeviceInfo.getModem().getParameters(11)); - values.addProperty("op_mode", protoDeviceInfo.getModem().getParameters(12)); - values.addProperty("nc_EARFCN", protoDeviceInfo.getModem().getParameters(13)); - values.addProperty("nc_EARNFCN_offset", protoDeviceInfo.getModem().getParameters(14)); - values.addProperty("nc_PCI", protoDeviceInfo.getModem().getParameters(15)); - values.addProperty("nc_RSRP", protoDeviceInfo.getModem().getParameters(16)); - values.addProperty("RLC_UL_BLER", protoDeviceInfo.getModem().getParameters(17)); - values.addProperty("RLC_DL_BLER", protoDeviceInfo.getModem().getParameters(18)); - values.addProperty("MAC_UL_BLER", protoDeviceInfo.getModem().getParameters(19)); - values.addProperty("MAC_DL_BLER", protoDeviceInfo.getModem().getParameters(20)); - values.addProperty("MAC_UL_TOTAL_BYTES", protoDeviceInfo.getModem().getParameters(21)); - values.addProperty("MAC_DL_TOTAL_BYTES", protoDeviceInfo.getModem().getParameters(22)); - values.addProperty("MAC_UL_total_HARQ_Tx", protoDeviceInfo.getModem().getParameters(23)); - values.addProperty("MAC_DL_total_HARQ_Tx", protoDeviceInfo.getModem().getParameters(24)); - values.addProperty("MAC_UL_HARQ_re_Tx", protoDeviceInfo.getModem().getParameters(25)); - values.addProperty("MAC_DL_HARQ_re_Tx", protoDeviceInfo.getModem().getParameters(26)); - values.addProperty("RLC_UL_tput", protoDeviceInfo.getModem().getParameters(27)); - values.addProperty("RLC_DL_tput", protoDeviceInfo.getModem().getParameters(28)); - values.addProperty("MAC_UL_tput", protoDeviceInfo.getModem().getParameters(29)); - values.addProperty("MAC_DL_tput", protoDeviceInfo.getModem().getParameters(30)); - values.addProperty("sleep_duration", protoDeviceInfo.getModem().getParameters(31)); - values.addProperty("rx_time", protoDeviceInfo.getModem().getParameters(32)); - values.addProperty("tx_time", protoDeviceInfo.getModem().getParameters(33)); + DeviceInfoProtos.ProtoModem modem = protoDeviceInfo.getModem(); + values.addProperty("modem_types", modem.getType().toString()); + values.addProperty("sc_EARNFCN_offset", modem.getParameters(0)); + values.addProperty("sc_EARFCN", modem.getParameters(1)); + values.addProperty("sc_PCI", modem.getParameters(2)); + values.addProperty("sc_Cell_id", modem.getParameters(3)); + values.addProperty("sc_RSRP", modem.getParameters(4)); + values.addProperty("sc_RSRQ", modem.getParameters(5)); + values.addProperty("sc_RSSI", modem.getParameters(6)); + values.addProperty("sc_SINR", modem.getParameters(7)); + values.addProperty("sc_Band", modem.getParameters(8)); + values.addProperty("sc_TAC", modem.getParameters(9)); + values.addProperty("sc_ECL", modem.getParameters(10)); + values.addProperty("sc_TX_PWR", modem.getParameters(11)); + values.addProperty("op_mode", modem.getParameters(12)); + values.addProperty("nc_EARFCN", modem.getParameters(13)); + values.addProperty("nc_EARNFCN_offset", modem.getParameters(14)); + values.addProperty("nc_PCI", modem.getParameters(15)); + values.addProperty("nc_RSRP", modem.getParameters(16)); + values.addProperty("RLC_UL_BLER", modem.getParameters(17)); + values.addProperty("RLC_DL_BLER", modem.getParameters(18)); + values.addProperty("MAC_UL_BLER", modem.getParameters(19)); + values.addProperty("MAC_DL_BLER", modem.getParameters(20)); + values.addProperty("MAC_UL_TOTAL_BYTES", modem.getParameters(21)); + values.addProperty("MAC_DL_TOTAL_BYTES", modem.getParameters(22)); + values.addProperty("MAC_UL_total_HARQ_Tx", modem.getParameters(23)); + values.addProperty("MAC_DL_total_HARQ_Tx", modem.getParameters(24)); + values.addProperty("MAC_UL_HARQ_re_Tx", modem.getParameters(25)); + values.addProperty("MAC_DL_HARQ_re_Tx", modem.getParameters(26)); + values.addProperty("RLC_UL_tput", modem.getParameters(27)); + values.addProperty("RLC_DL_tput", modem.getParameters(28)); + values.addProperty("MAC_UL_tput", modem.getParameters(29)); + values.addProperty("MAC_DL_tput", modem.getParameters(30)); + values.addProperty("sleep_duration", modem.getParameters(31)); + values.addProperty("rx_time", modem.getParameters(32)); + values.addProperty("tx_time", modem.getParameters(33)); //Runtime info DeviceInfoProtos.ProtoRuntime runtimeInfo = protoDeviceInfo.getRuntimeInfo(); @@ -415,156 +421,8 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { return new EfentoTelemetry(System.currentTimeMillis(), values); } - private JsonObject getEfentoConfiguration(ConfigProtos.ProtoConfig config) { - JsonObject values = new JsonObject(); - - values.addProperty("hash", config.getHash()); - values.addProperty("serial", CoapEfentoUtils.convertByteArrayToString(config.getSerialNumber().toByteArray())); - values.addProperty("timestamp", getDate(config.getHashTimestamp())); - values.addProperty("current_time", getDate(config.getCurrentTime())); - values.addProperty("apn", getString(config.getApn(), "\u007F", "Automatic")); - values.addProperty("token_config", getTokenConfigString(config.getCloudTokenConfig())); - values.addProperty("data_server", config.getDataServerIp() + ":" + config.getDataServerPort() + - "/" + config.getDataEndpoint()); - values.addProperty("update_server", config.getUpdateServerIp() + " Coap port " + - config.getUpdateServerPortCoap() + " Udp port " + config.getUpdateServerPortUdp()); - values.addProperty("device_info_endpoint", config.getDeviceInfoEndpoint()); - values.addProperty("configuration_endpoint", config.getConfigurationEndpoint()); - values.addProperty("time_endpoint", config.getTimeEndpoint()); - values.addProperty("transfer_limit", getStringValue(config.getTransferLimit(), 65535, "Disable")); - values.addProperty("plmn_selection", getPlmnSelection(config.getPlmnSelection())); - values.addProperty("supervision_period", getStringValue(config.getSupervisionPeriod(), 0xFFFFFFFF, "Functionality disabled")); - values.addProperty("modem_bands_mask", config.getModemBandsMask()); - values.addProperty("ACK", getStringValue(config.getAckInterval(), 0xFFFFFFFF, "Always request ACK")); - values.addProperty("ble_tx_power_level", config.getBleTxPowerLevel()); - values.addProperty("channel_types", config.getChannelTypesList().stream().map(Enum::toString).collect(Collectors.joining(","))); - values.addProperty("rules", config.getRulesList().stream().map(protoRule -> protoRule.getCondition().toString()).collect(Collectors.joining(","))); - values.addProperty("calendars", config.getCalendarsList().stream().map(protoCalendar -> protoCalendar.getType().toString()).collect(Collectors.joining(","))); - values.addProperty("cellular_config_params", config.getCellularConfigParamsList().stream().map(String::valueOf).collect(Collectors.joining(","))); - values.addProperty("dns_server_ip", config.getDnsServerIpList().stream().map(Object::toString).collect(Collectors.joining(","))); - values.addProperty("dns_ttl_config", getDnsTtlConfigString(config.getDnsTtlConfig())); - values.addProperty("token_coap_option", getStringValue(config.getCloudTokenCoapOption(), 65000, "Cloud token sent in the payload")); - values.addProperty("payload_signature_CoAP_option", getStringValue(config.getPayloadSignatureCoapOption(), 65000, "No payload signature in CoAP option")); - values.addProperty("payload_split_info", getPayloadSplitInfo(config.getPayloadSplitInfo())); - values.addProperty("led_config", config.getLedConfigList().stream().map(Object::toString).collect(Collectors.joining(","))); - values.addProperty("network_troubleshooting", getNetworkTroubleShooting(config.getNetworkTroubleshooting())); - values.addProperty("encryption_key", getEncryptionKey(config.getEncryptionKey().toByteArray())); - values.addProperty("apn_username", getString(config.getApnUserName(),"\u007F", "Automatic")); - values.addProperty("apn_password", getString(config.getApnPassword(),"\u007F", "Automatic")); - - return values; - } - - private String getStorageStatus(int status) { - String storageStatusString; - switch (status) { - case 0: - storageStatusString = "No errors"; - break; - case 1: - storageStatusString = "Nv storage has some corrupted packet. Memory is read-only"; - break; - case 2: - storageStatusString = "Nv storage is corrupted. Memory is unavailable"; - break; - default: - storageStatusString = String.valueOf(status); - } - return storageStatusString; - } - - private String getTokenConfigString(int tokenConfig) { - String tokenConfigString; - switch (tokenConfig) { - case 1: - tokenConfigString = "Cloud_token field value"; - break; - case 2: - tokenConfigString = "IMEI of the cellular module"; - break; - case 255: - tokenConfigString = "Do not send cloud_token field"; - break; - default: - tokenConfigString = String.valueOf(tokenConfig); - } - return tokenConfigString; - } - - private static String getString(String string, String marginalValue, String marginalDescription) { - String formatedString; - if (string.equals(marginalValue)) { - formatedString = marginalDescription; - } else { - formatedString = string; - } - return formatedString; - } - - private static String getEncryptionKey(byte[] bytes) { - String keyString; - if (Arrays.equals(bytes, new byte[] {0x7F})) { - keyString = "Encryption key disabled"; - } else { - keyString = CoapEfentoUtils.convertByteArrayToString(bytes); - } - return keyString; - } - - private static String getNetworkTroubleShooting(int networkTroubleShooting) { - String networkTroubleShootingString; - if (networkTroubleShooting == 1) { - networkTroubleShootingString = "Network troubleshooting disabled"; - } else if (networkTroubleShooting == 2) { - networkTroubleShootingString = "Network troubleshooting enabled"; - } else { - networkTroubleShootingString = String.valueOf(networkTroubleShooting); - } - return networkTroubleShootingString; - } - - private static String getPayloadSplitInfo(int info) { - String infoString; - if (info < 0) { - infoString = "Payload has been split, expect another part of the payload in the next message. The absolute value indicates an index of the current message."; - } else if (info == 0) { - infoString = "Payload has not been splitted"; - } else { - infoString = "Last part of the split payload, the value indicates the total number of the messages sent"; - } - return infoString; - } - - private static String getStringValue(int option, int marginalValue, String marginalDescription) { - String optionString; - if (option == marginalValue) { - optionString = marginalDescription; - } else { - optionString = String.valueOf(option); - } - return optionString; - } - - private static String getDnsTtlConfigString(int config) { - String configString; - if (config == 864001) { - configString = "Accept TTL from the DNS server (additionally, the DNS request when communication has failed)"; - } else if (config == 864002) { - configString = "DNS request is only after communication failed"; - } else { - configString = String.valueOf(config); - } - return configString; - } - - private static String getPlmnSelection(int selection) { - String selectionString; - if (selection == 1000000 || selection == 0xFFFFFFFF) { - selectionString = "automatic selection"; - } else { - selectionString = String.valueOf(selection); - } - return selectionString; + private JsonElement getEfentoConfiguration(byte[] bytes) throws InvalidProtocolBufferException { + return parseString(ProtoConverter.dynamicMsgToJson(bytes, ConfigProtos.getDescriptor().getMessageTypes().get(2))); } private static String getDate(long seconds) { @@ -580,7 +438,7 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { public static class EfentoTelemetry { private long ts; - private JsonObject values; + private JsonElement values; } } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java index fde2d69181..ce75608a7d 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/adaptor/EfentoCoapAdaptor.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.coap.efento.adaptor; import com.google.gson.Gson; -import com.google.gson.JsonObject; +import com.google.gson.JsonElement; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.adaptor.AdaptorException; @@ -33,16 +33,16 @@ public class EfentoCoapAdaptor { private static final Gson gson = new Gson(); - public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, List measurements) throws AdaptorException { + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(UUID sessionId, List telemetryList) throws AdaptorException { try { - return JsonConverter.convertToTelemetryProto(gson.toJsonTree(measurements)); + return JsonConverter.convertToTelemetryProto(gson.toJsonTree(telemetryList)); } catch (Exception ex) { log.warn("[{}] Failed to convert EfentoMeasurements to PostTelemetry request!", sessionId); throw new AdaptorException(ex); } } - public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, JsonObject deviceInfo) throws AdaptorException { + public TransportProtos.PostAttributeMsg convertToPostAttributes(UUID sessionId, JsonElement deviceInfo) throws AdaptorException { try { return JsonConverter.convertToAttributesProto(deviceInfo); } catch (Exception ex) { From 25778ce451f704c7f79ac235fc4c407d0de0aa95 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Tue, 1 Aug 2023 12:11:42 +0300 Subject: [PATCH 04/51] Moved unassign to async processing, added to customer controller, to unassign customer users alarms on customer removing --- .../server/controller/CustomerController.java | 26 ++++++++ .../entitiy/alarm/DefaultTbAlarmService.java | 66 +++++++++++-------- .../service/entitiy/alarm/TbAlarmService.java | 3 +- .../entitiy/user/DefaultUserService.java | 5 +- .../controller/AlarmControllerTest.java | 52 +++++++++++++++ 5 files changed, 122 insertions(+), 30 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index dd904add2e..4e351625c0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -17,6 +17,8 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; @@ -32,16 +34,21 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.entitiy.customer.TbCustomerService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import java.util.ArrayList; +import java.util.List; + import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES; @@ -64,6 +71,7 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI public class CustomerController extends BaseController { private final TbCustomerService tbCustomerService; + private final TbAlarmService tbAlarmService; public static final String IS_PUBLIC = "isPublic"; public static final String CUSTOMER_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the customer is owned by the same tenant. " + @@ -149,6 +157,24 @@ public class CustomerController extends BaseController { checkParameter(CUSTOMER_ID, strCustomerId); CustomerId customerId = new CustomerId(toUUID(strCustomerId)); Customer customer = checkCustomerId(customerId, Operation.DELETE); + TenantId tenantId = getTenantId(); + PageLink pl = new PageLink(100); + boolean hasNext = true; + List> futures = new ArrayList<>(); + + while (hasNext) { + PageData customerUsers = userService.findCustomerUsers(tenantId, customerId, pl); + for (User user : customerUsers.getData()) { + ListenableFuture future = tbAlarmService.unassignUserAlarms(tenantId, user, System.currentTimeMillis()); + futures.add(future); + } + hasNext = customerUsers.hasNext(); + if (hasNext) { + pl = pl.nextPageLink(); + } + } + ListenableFuture> allFutures = Futures.allAsList(futures); + Futures.getChecked(allFutures, ThingsboardException.class); tbCustomerService.delete(customer, getCurrentUser()); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 07c66e359a..a31fbf6a6d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -15,6 +15,9 @@ */ package org.thingsboard.server.service.entitiy.alarm; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -37,13 +40,11 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; @Service @AllArgsConstructor @@ -216,35 +217,44 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) { + public ListenableFuture unassignUserAlarms(TenantId tenantId, User user, long unassignTs) { AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); - try { - List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData(); - for (AlarmInfo alarm : alarms) { - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); - if (!result.isSuccessful()) { - continue; - } - if (result.isModified()) { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "ASSIGN")) - .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); + ListenableFuture> foundUserAlarmsFuture = alarmService.findAlarmsV2(tenantId, alarmQuery); + FutureCallback> callback = new FutureCallback<>() { + public void onSuccess(PageData alarmsData) { + for (AlarmInfo alarm : alarmsData.getData()) { + unassignUserAlarm(tenantId, user, unassignTs, alarm); } } - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new RuntimeException(e); + public void onFailure(Throwable t) { + log.error("Cannot get alarms for user {}", user.getId(), t); + } + }; + Futures.addCallback(foundUserAlarmsFuture, callback, dbExecutor); + return Futures.transform(foundUserAlarmsFuture, alarms -> null, dbExecutor); + } + + private void unassignUserAlarm(TenantId tenantId, User user, long unassignTs, AlarmInfo alarm) { + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); + if (!result.isSuccessful()) { + return; + } + if (result.isModified()) { + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) + .put("userId", user.getId().toString()) + .put("subtype", "ASSIGN")) + .build(); + try { + alarmCommentService.saveAlarmComment(alarm, alarmComment, user); + } catch (ThingsboardException e) { + log.error("Failed to save alarm comment", e); + } + notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 24af185539..5a3cf642c7 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.entitiy.alarm; +import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; @@ -38,7 +39,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; - void unassignUserAlarms(TenantId tenantId, User user, long unassignTs); + ListenableFuture unassignUserAlarms(TenantId tenantId, User user, long unassignTs); Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index d9f11dacb5..b87f1ebf8e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.service.entitiy.user; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -82,7 +84,8 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse UserId userId = tbUser.getId(); try { - tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis()); + ListenableFuture future = tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis()); + Futures.getChecked(future, ThingsboardException.class); userService.deleteUser(tenantId, userId); notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser, user, ActionType.DELETED, true, null, customerId.toString()); diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 6ce6e22e9a..18f082e54a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -625,6 +625,58 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); } + @Test + public void testUnassignAlarmOnCustomerRemoving() throws Exception { + createDifferentTenantCustomer(); + loginDifferentTenant(); + + User user = new User(); + user.setAuthority(Authority.CUSTOMER_USER); + user.setTenantId(tenantId); + user.setCustomerId(differentTenantCustomerId); + user.setEmail("customerForAssign@thingsboard.org"); + User savedUser = createUser(user, "password"); + + Device device = createDevice("Different customer device", "default", "differentTenantTest"); + + Device assignedDevice = doPost("/api/customer/" + differentTenantCustomerId.getId() + + "/device/" + device.getId().getId(), Device.class); + Assert.assertEquals(differentTenantCustomerId, assignedDevice.getCustomerId()); + + Alarm alarm = Alarm.builder() + .type(TEST_ALARM_TYPE) + .tenantId(savedDifferentTenant.getId()) + .customerId(differentTenantCustomerId) + .originator(device.getId()) + .severity(AlarmSeverity.MAJOR) + .build(); + alarm = doPost("/api/alarm", alarm, Alarm.class); + Assert.assertNotNull(alarm); + + alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(alarm); + + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + + beforeAssignmentTs = System.currentTimeMillis(); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/customer/" + differentTenantCustomerId.getId()).andExpect(status().isOk()); + + foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + } + @Test public void testFindAlarmsViaCustomerUser() throws Exception { loginCustomerUser(); From ed5b528964a14a0037781452136e2f25b9c255c6 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 3 Aug 2023 10:40:50 +0300 Subject: [PATCH 05/51] Updated unassign for alarms, on user removing to be transactional --- .../server/controller/CustomerController.java | 18 ------- .../entitiy/alarm/DefaultTbAlarmService.java | 47 ------------------- .../service/entitiy/alarm/TbAlarmService.java | 4 -- .../entitiy/user/DefaultUserService.java | 4 -- .../server/dao/alarm/AlarmService.java | 3 ++ .../server/dao/alarm/AlarmDao.java | 2 + .../server/dao/alarm/BaseAlarmService.java | 32 +++++++++++++ .../server/dao/sql/alarm/AlarmRepository.java | 3 ++ .../server/dao/sql/alarm/JpaAlarmDao.java | 6 +++ .../server/dao/user/UserServiceImpl.java | 1 + 10 files changed, 47 insertions(+), 73 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 4e351625c0..b9719f9e63 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -157,24 +157,6 @@ public class CustomerController extends BaseController { checkParameter(CUSTOMER_ID, strCustomerId); CustomerId customerId = new CustomerId(toUUID(strCustomerId)); Customer customer = checkCustomerId(customerId, Operation.DELETE); - TenantId tenantId = getTenantId(); - PageLink pl = new PageLink(100); - boolean hasNext = true; - List> futures = new ArrayList<>(); - - while (hasNext) { - PageData customerUsers = userService.findCustomerUsers(tenantId, customerId, pl); - for (User user : customerUsers.getData()) { - ListenableFuture future = tbAlarmService.unassignUserAlarms(tenantId, user, System.currentTimeMillis()); - futures.add(future); - } - hasNext = customerUsers.hasNext(); - if (hasNext) { - pl = pl.nextPageLink(); - } - } - ListenableFuture> allFutures = Futures.allAsList(futures); - Futures.getChecked(allFutures, ThingsboardException.class); tbCustomerService.delete(customer, getCurrentUser()); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index a31fbf6a6d..22a542b893 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -15,9 +15,6 @@ */ package org.thingsboard.server.service.entitiy.alarm; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -32,7 +29,6 @@ import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmInfo; -import org.thingsboard.server.common.data.alarm.AlarmQueryV2; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -40,8 +36,6 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; @@ -216,47 +210,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb return alarmInfo; } - @Override - public ListenableFuture unassignUserAlarms(TenantId tenantId, User user, long unassignTs) { - AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); - ListenableFuture> foundUserAlarmsFuture = alarmService.findAlarmsV2(tenantId, alarmQuery); - FutureCallback> callback = new FutureCallback<>() { - public void onSuccess(PageData alarmsData) { - for (AlarmInfo alarm : alarmsData.getData()) { - unassignUserAlarm(tenantId, user, unassignTs, alarm); - } - } - - public void onFailure(Throwable t) { - log.error("Cannot get alarms for user {}", user.getId(), t); - } - }; - Futures.addCallback(foundUserAlarmsFuture, callback, dbExecutor); - return Futures.transform(foundUserAlarmsFuture, alarms -> null, dbExecutor); - } - - private void unassignUserAlarm(TenantId tenantId, User user, long unassignTs, AlarmInfo alarm) { - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); - if (!result.isSuccessful()) { - return; - } - if (result.isModified()) { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "ASSIGN")) - .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); - } - } @Override public Boolean delete(Alarm alarm, User user) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 5a3cf642c7..a2ae9c8cc7 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -15,12 +15,10 @@ */ package org.thingsboard.server.service.entitiy.alarm; -import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; public interface TbAlarmService { @@ -39,7 +37,5 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; - ListenableFuture unassignUserAlarms(TenantId tenantId, User user, long unassignTs); - Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index b87f1ebf8e..85eb3bd680 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -15,8 +15,6 @@ */ package org.thingsboard.server.service.entitiy.user; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -84,8 +82,6 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse UserId userId = tbUser.getId(); try { - ListenableFuture future = tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis()); - Futures.getChecked(future, ThingsboardException.class); userService.deleteUser(tenantId, userId); notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser, user, ActionType.DELETED, true, null, customerId.toString()); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index fbf8892bd5..149c224201 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; @@ -118,6 +119,8 @@ public interface AlarmService extends EntityDaoService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); + void unassignUserAlarms(TenantId tenantId, UserId userId, long unassignTs); + void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); long countAlarmsByQuery(TenantId tenantId, CustomerId customerId, AlarmCountQuery query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 745861c6c8..3cfafa4ebd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -77,6 +77,8 @@ public interface AlarmDao extends Dao { PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); + List findAlarmByAssigneeId(UUID key); + void createEntityAlarmRecord(EntityAlarm entityAlarm); List findEntityAlarmRecords(TenantId tenantId, AlarmId id); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 96342aca2f..438334af24 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -25,9 +25,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmModificationRequest; @@ -84,6 +87,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private final TenantService tenantService; private final AlarmDao alarmDao; + private final AlarmCommentDao alarmCommentDao; private final EntityService entityService; private final DataValidator alarmDataValidator; @@ -308,6 +312,28 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return withPropagated(alarmDao.unassignAlarm(tenantId, alarmId, unassignTime)); } + @Override + public void unassignUserAlarms(TenantId tenantId, UserId userId, long unassignTs) { + List alarms = findAlarmsByAssigneeId(userId); + for (Alarm alarm : alarms) { + AlarmApiCallResult result = unassignAlarm(alarm.getTenantId(), alarm.getId(), unassignTs); + if (!result.isSuccessful()) { + continue; + } + if (result.isModified()) { + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode() + .put("text", "Alarm was unassigned because assigned user was deleted!") + .put("userId", userId.toString()) + .put("subtype", "ASSIGN")) + .build(); + alarmCommentDao.save(tenantId, alarmComment); + } + } + } + @Override public Alarm findAlarmById(TenantId tenantId, AlarmId alarmId) { log.trace("Executing findAlarmById [{}]", alarmId); @@ -488,4 +514,10 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } } + private List findAlarmsByAssigneeId(UserId userId) { + log.trace("Executing findAlarmsByAssigneeId [{}]", userId); + validateId(userId, "Incorrect alarmId " + userId); + return alarmDao.findAlarmByAssigneeId(userId.getId()); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 92537dc850..1479b396a7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -315,6 +315,9 @@ public interface AlarmRepository extends JpaRepository { @Query(value = "SELECT a FROM AlarmInfoEntity a WHERE a.tenantId = :tenantId AND a.id = :alarmId") AlarmInfoEntity findAlarmInfoById(@Param("tenantId") UUID tenantId, @Param("alarmId") UUID alarmId); + @Query("SELECT a FROM AlarmEntity a WHERE a.assigneeId = :assigneeId") + List findAlarmByAssigneeId(@Param("assigneeId") UUID assigneeId); + @Query(value = "SELECT create_or_update_active_alarm(:t_id, :c_id, :a_id, :a_created_ts, :a_o_id, :a_o_type, :a_type, :a_severity, " + ":a_start_ts, :a_end_ts, :a_details, :a_propagate, :a_propagate_to_owner, " + ":a_propagate_to_tenant, :a_propagation_types, :a_creation_enabled)", nativeQuery = true) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 8dfdaf8a3e..da5f6bcaf3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -285,6 +285,12 @@ public class JpaAlarmDao extends JpaAbstractDao implements A .mapData(AlarmId::new); } + @Override + public List findAlarmByAssigneeId(UUID key) { + List assignedAlarms = alarmRepository.findAlarmByAssigneeId(key); + return DaoUtil.convertDataList(assignedAlarms); + } + @Override public void createEntityAlarmRecord(EntityAlarm entityAlarm) { log.debug("Saving entity {}", entityAlarm); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 5dc32b8eed..22433bfce8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -230,6 +230,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic public void deleteUser(TenantId tenantId, UserId userId) { log.trace("Executing deleteUser [{}]", userId); validateId(userId, INCORRECT_USER_ID + userId); + alarmService.unassignUserAlarms(tenantId, userId, System.currentTimeMillis()); UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, userId.getId()); userCredentialsDao.removeById(tenantId, userCredentials.getUuidId()); userAuthSettingsDao.removeByUserId(userId); From fc7e1d88e6bd9c5b2f2f1fcfbdae79e49d3c99e0 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 3 Aug 2023 15:15:36 +0300 Subject: [PATCH 06/51] Optimized imports --- .../thingsboard/server/controller/CustomerController.java | 7 ------- .../org/thingsboard/server/dao/alarm/AlarmService.java | 1 - 2 files changed, 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index b9719f9e63..059f313936 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -17,8 +17,6 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; @@ -34,7 +32,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -46,9 +43,6 @@ import org.thingsboard.server.service.entitiy.customer.TbCustomerService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; -import java.util.ArrayList; -import java.util.List; - import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES; @@ -71,7 +65,6 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI public class CustomerController extends BaseController { private final TbCustomerService tbCustomerService; - private final TbAlarmService tbAlarmService; public static final String IS_PUBLIC = "isPublic"; public static final String CUSTOMER_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the customer is owned by the same tenant. " + diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 149c224201..93904582b2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.alarm; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; From 8ba6271ce0bbd49ffc61f92b73dcfa9624141e50 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 4 Aug 2023 13:38:35 +0300 Subject: [PATCH 07/51] Added ignore for exception, that can appear if sysadmin removed --- .../server/dao/alarm/BaseAlarmService.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 438334af24..751a5f01f3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -321,15 +321,17 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ continue; } if (result.isModified()) { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode() - .put("text", "Alarm was unassigned because assigned user was deleted!") - .put("userId", userId.toString()) - .put("subtype", "ASSIGN")) - .build(); - alarmCommentDao.save(tenantId, alarmComment); + try { + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode() + .put("text", "Alarm was unassigned because assigned user was deleted!") + .put("userId", userId.toString()) + .put("subtype", "ASSIGN")) + .build(); + alarmCommentDao.save(tenantId, alarmComment); + } catch (Exception ignored) {} } } } From 97d8171f0760a53139d0568f4546cc11ce6d5d77 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 9 Aug 2023 14:49:53 +0300 Subject: [PATCH 08/51] Refactored to use events --- .../entitiy/alarm/DefaultTbAlarmService.java | 74 +++++++++++-------- .../server/dao/alarm/AlarmService.java | 3 +- .../server/dao/alarm/BaseAlarmService.java | 41 ++-------- .../server/dao/user/UserServiceImpl.java | 1 - 4 files changed, 53 insertions(+), 66 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 9d6d36cfc9..c241fc3317 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -19,6 +19,7 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; @@ -33,9 +34,11 @@ import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; @@ -48,6 +51,9 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Autowired protected TbAlarmCommentService alarmCommentService; + @Autowired + protected UserService userService; + @Override public Alarm save(Alarm alarm, User user) throws ThingsboardException { ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED; @@ -217,45 +223,53 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) { - AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); - try { - List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData(); - for (AlarmInfo alarm : alarms) { - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); - if (!result.isSuccessful()) { - continue; - } - if (result.isModified()) { + public Boolean delete(Alarm alarm, User user) { + TenantId tenantId = alarm.getTenantId(); + notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), alarm, alarm.getCustomerId(), + ActionType.DELETED, user); + return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); + } + + @TransactionalEventListener + public void unassignDeletedUserAlarms(UserId userId) { + List alarms = alarmService.findAlarmsByAssigneeId(userId); + for (Alarm alarm : alarms) { + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(alarm.getTenantId(), alarm.getId(), System.currentTimeMillis()); + if (!result.isSuccessful()) { + continue; + } + if (result.isModified()) { + try { AlarmComment alarmComment = AlarmComment.builder() .alarmId(alarm.getId()) .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) + .comment(JacksonUtil.newObjectNode() + .put("text", String.format("Alarm was unassigned because user with id %s - was deleted", + userId.toString())) + .put("userId", userId.toString()) .put("subtype", "ASSIGN")) .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } - notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(), - alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, user); + alarmCommentService.saveAlarmComment(alarm, alarmComment, null); + } catch (ThingsboardException e) { + log.error("Failed to save alarm comment", e); } + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(), + alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, null); } - - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new RuntimeException(e); } } - @Override - public Boolean delete(Alarm alarm, User user) { - TenantId tenantId = alarm.getTenantId(); - notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), alarm, alarm.getCustomerId(), - ActionType.DELETED, user); - return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); + @TransactionalEventListener(fallbackExecution = true) + public void handleEvent(DeleteEntityEvent event) { + try { + log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); + EntityId entityId = event.getEntityId(); + if (EntityType.USER.equals(entityId.getEntityType())) { + unassignDeletedUserAlarms((UserId) entityId); + } + } catch (Exception e) { + log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event); + } } private static long getOrDefault(long ts) { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 93904582b2..212f544d29 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.Collection; +import java.util.List; public interface AlarmService extends EntityDaoService { @@ -118,7 +119,7 @@ public interface AlarmService extends EntityDaoService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); - void unassignUserAlarms(TenantId tenantId, UserId userId, long unassignTs); + List findAlarmsByAssigneeId(UserId userId); void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index edd7295613..b7bdaa3078 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -25,12 +25,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; -import org.thingsboard.server.common.data.alarm.AlarmComment; -import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmModificationRequest; @@ -347,30 +344,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return result; } - @Override - public void unassignUserAlarms(TenantId tenantId, UserId userId, long unassignTs) { - List alarms = findAlarmsByAssigneeId(userId); - for (Alarm alarm : alarms) { - AlarmApiCallResult result = unassignAlarm(alarm.getTenantId(), alarm.getId(), unassignTs); - if (!result.isSuccessful()) { - continue; - } - if (result.isModified()) { - try { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode() - .put("text", "Alarm was unassigned because assigned user was deleted!") - .put("userId", userId.toString()) - .put("subtype", "ASSIGN")) - .build(); - alarmCommentDao.save(tenantId, alarmComment); - } catch (Exception ignored) {} - } - } - } - @Override public Alarm findAlarmById(TenantId tenantId, AlarmId alarmId) { log.trace("Executing findAlarmById [{}]", alarmId); @@ -412,6 +385,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return Futures.immediateFuture(alarmDao.findCustomerAlarmsV2(tenantId, customerId, query)); } + @Override + public List findAlarmsByAssigneeId(UserId userId) { + log.trace("Executing findAlarmsByAssigneeId [{}]", userId); + validateId(userId, "Incorrect alarmId " + userId); + return alarmDao.findAlarmByAssigneeId(userId.getId()); + } + @Override public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, String assigneeId) { @@ -550,11 +530,4 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ request.setEndTs(request.getStartTs()); } } - - private List findAlarmsByAssigneeId(UserId userId) { - log.trace("Executing findAlarmsByAssigneeId [{}]", userId); - validateId(userId, "Incorrect alarmId " + userId); - return alarmDao.findAlarmByAssigneeId(userId.getId()); - } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 5f1bc605bc..5afcc49def 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -249,7 +249,6 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic public void deleteUser(TenantId tenantId, UserId userId) { log.trace("Executing deleteUser [{}]", userId); validateId(userId, INCORRECT_USER_ID + userId); - alarmService.unassignUserAlarms(tenantId, userId, System.currentTimeMillis()); UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, userId.getId()); userCredentialsDao.removeById(tenantId, userCredentials.getUuidId()); userAuthSettingsDao.removeByUserId(userId); From 057729602ed5c1f9ee7e21b417219dcb9fdd0e47 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 9 Aug 2023 16:32:48 +0300 Subject: [PATCH 09/51] Imports --- .../org/thingsboard/server/controller/CustomerController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 059f313936..dd904add2e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -38,7 +38,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.entitiy.customer.TbCustomerService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; From 93ceb4befdb580fb2c5c2b43589d577f387e24f6 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 10 Aug 2023 07:56:09 +0300 Subject: [PATCH 10/51] Refactoring --- .../server/service/entitiy/alarm/DefaultTbAlarmService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index c241fc3317..9e4ad00ad3 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -230,8 +230,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); } - @TransactionalEventListener - public void unassignDeletedUserAlarms(UserId userId) { + private void unassignDeletedUserAlarms(UserId userId) { List alarms = alarmService.findAlarmsByAssigneeId(userId); for (Alarm alarm : alarms) { AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(alarm.getTenantId(), alarm.getId(), System.currentTimeMillis()); From bd3c249fb259f3cedf0f0579c0f804637853c21d Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 10 Aug 2023 08:25:04 +0300 Subject: [PATCH 11/51] Removed uneccessary import service --- .../server/service/entitiy/alarm/DefaultTbAlarmService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 9e4ad00ad3..9cd7b2efac 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -38,7 +38,6 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; -import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; @@ -51,9 +50,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Autowired protected TbAlarmCommentService alarmCommentService; - @Autowired - protected UserService userService; - @Override public Alarm save(Alarm alarm, User user) throws ThingsboardException { ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED; From c9a7ca62bcd1cba27f4ac8fc92a4c889f8a37141 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 10 Aug 2023 08:33:30 +0300 Subject: [PATCH 12/51] Removed uneccessary import --- .../java/org/thingsboard/server/dao/alarm/BaseAlarmService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index b7bdaa3078..106e37f278 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -88,7 +88,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private final TenantService tenantService; private final AlarmDao alarmDao; - private final AlarmCommentDao alarmCommentDao; private final EntityService entityService; private final DataValidator alarmDataValidator; From 328d53dffc47150ccf745b88765625c59e2adc8d Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 11 Aug 2023 07:52:03 +0300 Subject: [PATCH 13/51] Changed alarms unassign method to returen ids instead of Alarm objects and changed to use entity from deleted entity event --- .../entitiy/alarm/DefaultTbAlarmService.java | 18 ++++++++++-------- .../server/dao/alarm/AlarmService.java | 2 +- .../thingsboard/server/dao/alarm/AlarmDao.java | 2 +- .../server/dao/alarm/BaseAlarmService.java | 6 +++--- .../server/dao/sql/alarm/AlarmRepository.java | 4 ++-- .../server/dao/sql/alarm/JpaAlarmDao.java | 7 ++++--- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 9cd7b2efac..f1f8ba038c 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; @@ -226,22 +227,23 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); } - private void unassignDeletedUserAlarms(UserId userId) { - List alarms = alarmService.findAlarmsByAssigneeId(userId); - for (Alarm alarm : alarms) { - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(alarm.getTenantId(), alarm.getId(), System.currentTimeMillis()); + private void unassignDeletedUserAlarms(User user) { + List alarmIds = alarmService.findAlarmIdsByAssigneeId(user.getId()); + for (AlarmId alarmId : alarmIds) { + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, System.currentTimeMillis()); + Alarm alarm = result.getAlarm(); if (!result.isSuccessful()) { continue; } if (result.isModified()) { try { AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) + .alarmId(alarmId) .type(AlarmCommentType.SYSTEM) .comment(JacksonUtil.newObjectNode() .put("text", String.format("Alarm was unassigned because user with id %s - was deleted", - userId.toString())) - .put("userId", userId.toString()) + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) + .put("userId", user.getId().toString()) .put("subtype", "ASSIGN")) .build(); alarmCommentService.saveAlarmComment(alarm, alarmComment, null); @@ -260,7 +262,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); EntityId entityId = event.getEntityId(); if (EntityType.USER.equals(entityId.getEntityType())) { - unassignDeletedUserAlarms((UserId) entityId); + unassignDeletedUserAlarms((User) event.getEntity()); } } catch (Exception e) { log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 212f544d29..7bfdeaa523 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -119,7 +119,7 @@ public interface AlarmService extends EntityDaoService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); - List findAlarmsByAssigneeId(UserId userId); + List findAlarmIdsByAssigneeId(UserId userId); void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 3cfafa4ebd..2e8844701c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -77,7 +77,7 @@ public interface AlarmDao extends Dao { PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); - List findAlarmByAssigneeId(UUID key); + List findAlarmIdsByAssigneeId(UUID key); void createEntityAlarmRecord(EntityAlarm entityAlarm); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 106e37f278..f36b56ca7a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -385,10 +385,10 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } @Override - public List findAlarmsByAssigneeId(UserId userId) { - log.trace("Executing findAlarmsByAssigneeId [{}]", userId); + public List findAlarmIdsByAssigneeId(UserId userId) { + log.trace("Executing findAlarmIdsByAssigneeId [{}]", userId); validateId(userId, "Incorrect alarmId " + userId); - return alarmDao.findAlarmByAssigneeId(userId.getId()); + return alarmDao.findAlarmIdsByAssigneeId(userId.getId()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 1479b396a7..b35ca52e79 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -315,8 +315,8 @@ public interface AlarmRepository extends JpaRepository { @Query(value = "SELECT a FROM AlarmInfoEntity a WHERE a.tenantId = :tenantId AND a.id = :alarmId") AlarmInfoEntity findAlarmInfoById(@Param("tenantId") UUID tenantId, @Param("alarmId") UUID alarmId); - @Query("SELECT a FROM AlarmEntity a WHERE a.assigneeId = :assigneeId") - List findAlarmByAssigneeId(@Param("assigneeId") UUID assigneeId); + @Query("SELECT a.id FROM AlarmEntity a WHERE a.assigneeId = :assigneeId") + List findAlarmIdsByAssigneeId(@Param("assigneeId") UUID assigneeId); @Query(value = "SELECT create_or_update_active_alarm(:t_id, :c_id, :a_id, :a_created_ts, :a_o_id, :a_o_type, :a_type, :a_severity, " + ":a_start_ts, :a_end_ts, :a_details, :a_propagate, :a_propagate_to_owner, " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index da5f6bcaf3..045297f4ba 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -66,6 +66,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * Created by Valerii Sosliuk on 5/19/2017. @@ -286,9 +287,9 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } @Override - public List findAlarmByAssigneeId(UUID key) { - List assignedAlarms = alarmRepository.findAlarmByAssigneeId(key); - return DaoUtil.convertDataList(assignedAlarms); + public List findAlarmIdsByAssigneeId(UUID key) { + List assignedAlarmIds = alarmRepository.findAlarmIdsByAssigneeId(key); + return assignedAlarmIds.stream().map(AlarmId::new).collect(Collectors.toList()); } @Override From e7543d78d403dd53c71511cac5c0dcd7aa16fbeb Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 11 Aug 2023 07:56:08 +0300 Subject: [PATCH 14/51] Changed method for user removing, added user as an entity to deleted entity event --- .../service/entitiy/user/DefaultUserService.java | 4 ++-- .../org/thingsboard/server/dao/user/UserService.java | 10 +++++----- .../thingsboard/server/dao/user/UserServiceImpl.java | 10 ++++++---- .../server/dao/service/UserServiceTest.java | 12 ++++++------ 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index fde39200bd..cc026e08ad 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -64,7 +64,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse try { mailService.sendActivationEmail(activateUrl, email); } catch (ThingsboardException e) { - userService.deleteUser(tenantId, savedUser.getId()); + userService.deleteUser(tenantId, savedUser); throw e; } } @@ -82,7 +82,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse UserId userId = tbUser.getId(); try { - userService.deleteUser(tenantId, userId); + userService.deleteUser(tenantId, tbUser); notificationEntityService.logEntityAction(tenantId, userId, tbUser, customerId, actionType, user, customerId.toString()); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 47a7423191..3ef93dc2f7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -30,7 +30,7 @@ import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; public interface UserService extends EntityDaoService { - + User findUserById(TenantId tenantId, UserId userId); ListenableFuture findUserByIdAsync(TenantId tenantId, UserId userId); @@ -42,22 +42,22 @@ public interface UserService extends EntityDaoService { User saveUser(TenantId tenantId, User user); UserCredentials findUserCredentialsByUserId(TenantId tenantId, UserId userId); - + UserCredentials findUserCredentialsByActivateToken(TenantId tenantId, String activateToken); UserCredentials findUserCredentialsByResetToken(TenantId tenantId, String resetToken); UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials); - + UserCredentials activateUserCredentials(TenantId tenantId, String activateToken, String password); - + UserCredentials requestPasswordReset(TenantId tenantId, String email); UserCredentials requestExpiredPasswordReset(TenantId tenantId, UserCredentialsId userCredentialsId); UserCredentials replaceUserCredentials(TenantId tenantId, UserCredentials userCredentials); - void deleteUser(TenantId tenantId, UserId userId); + void deleteUser(TenantId tenantId, User user); PageData findUsersByTenantId(TenantId tenantId, PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 5afcc49def..295bdc4849 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -246,7 +246,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic @Override @Transactional - public void deleteUser(TenantId tenantId, UserId userId) { + public void deleteUser(TenantId tenantId, User user) { + UserId userId = user.getId(); log.trace("Executing deleteUser [{}]", userId); validateId(userId, INCORRECT_USER_ID + userId); UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, userId.getId()); @@ -258,7 +259,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic countService.publishCountEntityEvictEvent(tenantId, EntityType.USER); eventPublisher.publishEvent(DeleteEntityEvent.builder() .tenantId(tenantId) - .entityId(userId).build()); + .entityId(userId) + .entity(user).build()); } @Override @@ -443,7 +445,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic @Override protected void removeEntity(TenantId tenantId, User entity) { - deleteUser(tenantId, new UserId(entity.getUuidId())); + deleteUser(tenantId, entity); } }; @@ -456,7 +458,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic @Override protected void removeEntity(TenantId tenantId, User entity) { - deleteUser(tenantId, new UserId(entity.getUuidId())); + deleteUser(tenantId, entity); } }; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java index c423147474..5a8286a449 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java @@ -135,7 +135,7 @@ public class UserServiceTest extends AbstractServiceTest { Assert.assertEquals("Joe", savedUser.getFirstName()); Assert.assertEquals("Downs", savedUser.getLastName()); - userService.deleteUser(tenantId, savedUser.getId()); + userService.deleteUser(tenantId, savedUser); } @Test @@ -188,7 +188,7 @@ public class UserServiceTest extends AbstractServiceTest { Assert.assertNotNull(foundUser); UserCredentials userCredentials = userService.findUserCredentialsByUserId(tenantId, foundUser.getId()); Assert.assertNotNull(userCredentials); - userService.deleteUser(tenantId, foundUser.getId()); + userService.deleteUser(tenantId, foundUser); userCredentials = userService.findUserCredentialsByUserId(tenantId, foundUser.getId()); foundUser = userService.findUserById(tenantId, foundUser.getId()); Assert.assertNull(foundUser); @@ -301,7 +301,7 @@ public class UserServiceTest extends AbstractServiceTest { Assert.assertEquals(tenantAdminsEmail2, loadedTenantAdminsEmail2); for (User user : loadedTenantAdminsEmail1) { - userService.deleteUser(tenantId, user.getId()); + userService.deleteUser(tenantId, user); } pageLink = new PageLink(4, 0, email1); @@ -310,7 +310,7 @@ public class UserServiceTest extends AbstractServiceTest { Assert.assertEquals(0, pageData.getData().size()); for (User user : loadedTenantAdminsEmail2) { - userService.deleteUser(tenantId, user.getId()); + userService.deleteUser(tenantId, user); } pageLink = new PageLink(4, 0, email2); @@ -440,7 +440,7 @@ public class UserServiceTest extends AbstractServiceTest { Assert.assertEquals(customerUsersEmail2, loadedCustomerUsersEmail2); for (User user : loadedCustomerUsersEmail1) { - userService.deleteUser(tenantId, user.getId()); + userService.deleteUser(tenantId, user); } pageLink = new PageLink(4, 0, email1); @@ -449,7 +449,7 @@ public class UserServiceTest extends AbstractServiceTest { Assert.assertEquals(0, pageData.getData().size()); for (User user : loadedCustomerUsersEmail2) { - userService.deleteUser(tenantId, user.getId()); + userService.deleteUser(tenantId, user); } pageLink = new PageLink(4, 0, email2); From 19c5e5088403a39615dcdde61831e136bbb71163 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Tue, 15 Aug 2023 18:24:38 +0300 Subject: [PATCH 15/51] Updated due to comments --- .../entitiy/alarm/DefaultTbAlarmService.java | 35 +++++---- .../service/entitiy/alarm/TbAlarmService.java | 5 ++ .../InMemoryHouseKeeperServiceService.java | 73 +++++++++++++++++++ .../dao/housekeeper/HouseKeeperService.java | 27 +++++++ .../org/thingsboard/server/dao/DaoUtil.java | 5 ++ .../server/dao/sql/alarm/JpaAlarmDao.java | 2 +- 6 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index f1f8ba038c..48e496c05b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; @@ -51,6 +52,9 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Autowired protected TbAlarmCommentService alarmCommentService; + @Autowired + private HouseKeeperService housekeeper; + @Override public Alarm save(Alarm alarm, User user) throws ThingsboardException { ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED; @@ -220,16 +224,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public Boolean delete(Alarm alarm, User user) { - TenantId tenantId = alarm.getTenantId(); - notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), alarm, alarm.getCustomerId(), - ActionType.DELETED, user); - return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); - } - - private void unassignDeletedUserAlarms(User user) { + public List unassignDeletedUserAlarms(User user) { List alarmIds = alarmService.findAlarmIdsByAssigneeId(user.getId()); for (AlarmId alarmId : alarmIds) { + log.trace("[{}] Unassigning alarm {} userId {}", user.getTenantId().getId(), alarmId.getId(), user.getId().getId()); AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, System.currentTimeMillis()); Alarm alarm = result.getAlarm(); if (!result.isSuccessful()) { @@ -254,21 +252,26 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, null); } } + return alarmIds; } @TransactionalEventListener(fallbackExecution = true) public void handleEvent(DeleteEntityEvent event) { - try { - log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); - EntityId entityId = event.getEntityId(); - if (EntityType.USER.equals(entityId.getEntityType())) { - unassignDeletedUserAlarms((User) event.getEntity()); - } - } catch (Exception e) { - log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event); + log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); + EntityId entityId = event.getEntityId(); + if (EntityType.USER.equals(entityId.getEntityType())) { + housekeeper.unassignDeletedUserAlarms((User) event.getEntity()); } } + @Override + public Boolean delete(Alarm alarm, User user) { + TenantId tenantId = alarm.getTenantId(); + notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), alarm, alarm.getCustomerId(), + ActionType.DELETED, user); + return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); + } + private static long getOrDefault(long ts) { return ts > 0 ? ts : System.currentTimeMillis(); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index a2ae9c8cc7..c531c20c53 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -19,8 +19,11 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.UserId; +import java.util.List; + public interface TbAlarmService { Alarm save(Alarm entity, User user) throws ThingsboardException; @@ -37,5 +40,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; + List unassignDeletedUserAlarms(User user); + Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java new file mode 100644 index 0000000000..2e62a68333 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2023 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.service.housekeeper; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.dao.housekeeper.HouseKeeperService; +import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +@Component +@RequiredArgsConstructor +@Slf4j +public class InMemoryHouseKeeperServiceService implements HouseKeeperService { + + @Lazy + final TbAlarmService alarmService; + + ListeningExecutorService executor; + + AtomicInteger queueSize = new AtomicInteger(); + + @PostConstruct + public void init() { + executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("housekeeper"))); + } + + @PreDestroy + public void destroy() { + if (executor != null) { + executor.shutdown(); + } + } + + @Override + public ListenableFuture> unassignDeletedUserAlarms(User user) { + log.debug("[{}][{}] unassignDeletedUserAlarms submitting, pending queue size: {} ", user.getTenantId().getId(), user.getId().getId(), queueSize.get()); + queueSize.incrementAndGet(); + ListenableFuture> future = executor.submit(() -> alarmService.unassignDeletedUserAlarms(user)); + future.addListener(() -> { + queueSize.decrementAndGet(); + log.debug("[{}][{}] unassignDeletedUserAlarms finished, pending queue size: {} ", user.getTenantId().getId(), user.getId().getId(), queueSize.get()); + }, MoreExecutors.directExecutor()); + return future; + } + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java new file mode 100644 index 0000000000..3ffd309ca5 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2023 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.dao.housekeeper; + +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.id.AlarmId; + +import java.util.List; + +public interface HouseKeeperService { + ListenableFuture> unassignDeletedUserAlarms(User user); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java index 63b13bca66..9688f7b7e1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java @@ -33,6 +33,7 @@ import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Collectors; public abstract class DaoUtil { @@ -109,6 +110,10 @@ public abstract class DaoUtil { return ids; } + public static List fromUUIDs(List uuids, Function mapper) { + return uuids.stream().map(mapper).collect(Collectors.toList()); + } + public static I toEntityId(UUID uuid, Function creator) { if (uuid != null) { return creator.apply(uuid); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 045297f4ba..ed25595442 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -289,7 +289,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A @Override public List findAlarmIdsByAssigneeId(UUID key) { List assignedAlarmIds = alarmRepository.findAlarmIdsByAssigneeId(key); - return assignedAlarmIds.stream().map(AlarmId::new).collect(Collectors.toList()); + return DaoUtil.fromUUIDs(assignedAlarmIds, AlarmId::new); } @Override From 4b8db9f37d182849de729cd5fb2c710ca9c6f181 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 16 Aug 2023 09:09:40 +0300 Subject: [PATCH 16/51] Refactored repository method for getting assigned alarms, added limitations, logs and adopted tests for event based model alarms unassigning on user removing --- .../entitiy/alarm/DefaultTbAlarmService.java | 64 +++++++++-------- .../service/entitiy/alarm/TbAlarmService.java | 3 +- .../InMemoryHouseKeeperServiceService.java | 34 +++++++-- .../controller/AlarmControllerTest.java | 71 ++++++++++++------- .../server/dao/alarm/AlarmService.java | 2 +- .../dao/housekeeper/HouseKeeperService.java | 4 +- .../server/dao/user/UserService.java | 20 +++--- .../server/dao/alarm/AlarmDao.java | 2 +- .../server/dao/alarm/BaseAlarmService.java | 6 +- .../server/dao/sql/alarm/AlarmRepository.java | 2 +- .../server/dao/sql/alarm/JpaAlarmDao.java | 6 +- 11 files changed, 134 insertions(+), 80 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 48e496c05b..65302222fc 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -42,6 +42,7 @@ import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; +import java.util.ArrayList; import java.util.List; @Service @@ -224,43 +225,50 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public List unassignDeletedUserAlarms(User user) { - List alarmIds = alarmService.findAlarmIdsByAssigneeId(user.getId()); - for (AlarmId alarmId : alarmIds) { - log.trace("[{}] Unassigning alarm {} userId {}", user.getTenantId().getId(), alarmId.getId(), user.getId().getId()); - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, System.currentTimeMillis()); - Alarm alarm = result.getAlarm(); - if (!result.isSuccessful()) { - continue; - } - if (result.isModified()) { - try { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarmId) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode() - .put("text", String.format("Alarm was unassigned because user with id %s - was deleted", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "ASSIGN")) - .build(); - alarmCommentService.saveAlarmComment(alarm, alarmComment, null); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); + public List unassignDeletedUserAlarms(TenantId tenantId, User user) { + List totalAlarmIds = new ArrayList<>(); + List alarmIds; + do { + alarmIds = alarmService.findAlarmIdsByAssigneeId(tenantId, user.getId(), 100); + for (AlarmId alarmId : alarmIds) { + log.trace("[{}] Unassigning alarm {} userId {}", tenantId, alarmId.getId(), user.getId().getId()); + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, System.currentTimeMillis()); + Alarm alarm = result.getAlarm(); + if (!result.isSuccessful()) { + continue; } - notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(), - alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, null); + if (result.isModified()) { + try { + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarmId) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode() + .put("text", String.format("Alarm was unassigned because user with id %s - was deleted", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) + .put("userId", user.getId().toString()) + .put("subtype", "ASSIGN")) + .build(); + alarmCommentService.saveAlarmComment(alarm, alarmComment, null); + } catch (ThingsboardException e) { + log.error("Failed to save alarm comment", e); + } + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(), + alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, null); + } + + totalAlarmIds.addAll(alarmIds); } } - return alarmIds; + while (!alarmIds.isEmpty()); + return totalAlarmIds; } @TransactionalEventListener(fallbackExecution = true) public void handleEvent(DeleteEntityEvent event) { - log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); + log.trace("[{}] DeleteEntityEvent handler: {}", event.getTenantId(), event); EntityId entityId = event.getEntityId(); if (EntityType.USER.equals(entityId.getEntityType())) { - housekeeper.unassignDeletedUserAlarms((User) event.getEntity()); + housekeeper.unassignDeletedUserAlarms(event.getTenantId(), (User) event.getEntity()); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index c531c20c53..c5eb6714ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import java.util.List; @@ -40,7 +41,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; - List unassignDeletedUserAlarms(User user); + List unassignDeletedUserAlarms(TenantId tenantId, User user); Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java index 2e62a68333..ad3bff921e 100644 --- a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java @@ -15,16 +15,20 @@ */ package org.thingsboard.server.service.housekeeper; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; @@ -45,27 +49,43 @@ public class InMemoryHouseKeeperServiceService implements HouseKeeperService { ListeningExecutorService executor; AtomicInteger queueSize = new AtomicInteger(); + AtomicInteger totalProcessedCounter = new AtomicInteger(); @PostConstruct public void init() { - executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("housekeeper"))); + log.debug("Starting HouseKeeper service"); + executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("housekeeper"))); } @PreDestroy public void destroy() { if (executor != null) { + log.debug("Stopping HouseKeeper service"); executor.shutdown(); } } @Override - public ListenableFuture> unassignDeletedUserAlarms(User user) { - log.debug("[{}][{}] unassignDeletedUserAlarms submitting, pending queue size: {} ", user.getTenantId().getId(), user.getId().getId(), queueSize.get()); + public ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user) { + log.debug("[{}][{}] unassignDeletedUserAlarms submitting, pending queue size: {} ", tenantId, user.getId().getId(), queueSize.get()); queueSize.incrementAndGet(); - ListenableFuture> future = executor.submit(() -> alarmService.unassignDeletedUserAlarms(user)); - future.addListener(() -> { - queueSize.decrementAndGet(); - log.debug("[{}][{}] unassignDeletedUserAlarms finished, pending queue size: {} ", user.getTenantId().getId(), user.getId().getId(), queueSize.get()); + ListenableFuture> future = executor.submit(() -> alarmService.unassignDeletedUserAlarms(tenantId, user)); + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(List alarmIds) { + queueSize.decrementAndGet(); + totalProcessedCounter.incrementAndGet(); + log.debug("[{}][{}] unassignDeletedUserAlarms finished, pending queue size: {}, total processed count: {} ", + tenantId, user.getId().getId(), queueSize.get(), totalProcessedCounter.get()); + } + + @Override + public void onFailure(@NotNull Throwable throwable) { + queueSize.decrementAndGet(); + totalProcessedCounter.incrementAndGet(); + log.error("[{}][{}] unassignDeletedUserAlarms failed, pending queue size: {}, total processed count: {}", + tenantId, user.getId().getId(), queueSize.get(), totalProcessedCounter.get(), throwable); + } }, MoreExecutors.directExecutor()); return future; } diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 7cf8e05503..ea66bcfcc2 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -29,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; +import org.testcontainers.shaded.org.awaitility.Awaitility; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; @@ -46,6 +47,7 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.TimeUnit; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -568,10 +570,13 @@ public class AlarmControllerTest extends AbstractControllerTest { long beforeAssignmentTs = System.currentTimeMillis(); doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); - AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); - Assert.assertNotNull(foundAlarm); - Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + Alarm finalAlarm = alarm; + var alarmObj = new Object() { + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); + }; + Assert.assertNotNull(alarmObj.foundAlarm); + Assert.assertEquals(savedUser.getId(), alarmObj.foundAlarm.getAssigneeId()); + Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); @@ -583,10 +588,14 @@ public class AlarmControllerTest extends AbstractControllerTest { loginDifferentTenant(); - foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); - Assert.assertNotNull(foundAlarm); - Assert.assertNull(foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> { + alarmObj.foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); + return alarmObj.foundAlarm.getAssigneeId() == null; + }); + + Assert.assertNotNull(alarmObj.foundAlarm); + Assert.assertNull(alarmObj.foundAlarm.getAssigneeId()); + Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test @@ -617,10 +626,13 @@ public class AlarmControllerTest extends AbstractControllerTest { long beforeAssignmentTs = System.currentTimeMillis(); doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); - AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); - Assert.assertNotNull(foundAlarm); - Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + Alarm finalAlarm = alarm; + var alarmObj = new Object() { + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); + }; + Assert.assertNotNull(alarmObj.foundAlarm); + Assert.assertEquals(savedUser.getId(), alarmObj.foundAlarm.getAssigneeId()); + Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); @@ -628,10 +640,14 @@ public class AlarmControllerTest extends AbstractControllerTest { doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); - foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); - Assert.assertNotNull(foundAlarm); - Assert.assertNull(foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> { + alarmObj.foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); + return alarmObj.foundAlarm.getAssigneeId() == null; + }); + + Assert.assertNotNull(alarmObj.foundAlarm); + Assert.assertNull(alarmObj.foundAlarm.getAssigneeId()); + Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test @@ -669,10 +685,13 @@ public class AlarmControllerTest extends AbstractControllerTest { long beforeAssignmentTs = System.currentTimeMillis(); doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); - AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); - Assert.assertNotNull(foundAlarm); - Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + Alarm finalAlarm = alarm; + var alarmObj = new Object() { + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); + }; + Assert.assertNotNull(alarmObj.foundAlarm); + Assert.assertEquals(savedUser.getId(), alarmObj.foundAlarm.getAssigneeId()); + Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); @@ -680,10 +699,14 @@ public class AlarmControllerTest extends AbstractControllerTest { doDelete("/api/customer/" + differentTenantCustomerId.getId()).andExpect(status().isOk()); - foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); - Assert.assertNotNull(foundAlarm); - Assert.assertNull(foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> { + alarmObj.foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); + return alarmObj.foundAlarm.getAssigneeId() == null; + }); + + Assert.assertNotNull(alarmObj.foundAlarm); + Assert.assertNull(alarmObj.foundAlarm.getAssigneeId()); + Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 7bfdeaa523..95e46d66ff 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -119,7 +119,7 @@ public interface AlarmService extends EntityDaoService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); - List findAlarmIdsByAssigneeId(UserId userId); + List findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, int limit); void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java index 3ffd309ca5..41f6136c90 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java @@ -18,10 +18,12 @@ package org.thingsboard.server.dao.housekeeper; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; import java.util.List; public interface HouseKeeperService { - ListenableFuture> unassignDeletedUserAlarms(User user); + + ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 3ef93dc2f7..b874e038d2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -31,27 +31,27 @@ import java.util.List; public interface UserService extends EntityDaoService { - User findUserById(TenantId tenantId, UserId userId); + User findUserById(TenantId tenantId, UserId userId); - ListenableFuture findUserByIdAsync(TenantId tenantId, UserId userId); + ListenableFuture findUserByIdAsync(TenantId tenantId, UserId userId); - User findUserByEmail(TenantId tenantId, String email); + User findUserByEmail(TenantId tenantId, String email); User findUserByTenantIdAndEmail(TenantId tenantId, String email); - User saveUser(TenantId tenantId, User user); + User saveUser(TenantId tenantId, User user); - UserCredentials findUserCredentialsByUserId(TenantId tenantId, UserId userId); + UserCredentials findUserCredentialsByUserId(TenantId tenantId, UserId userId); - UserCredentials findUserCredentialsByActivateToken(TenantId tenantId, String activateToken); + UserCredentials findUserCredentialsByActivateToken(TenantId tenantId, String activateToken); - UserCredentials findUserCredentialsByResetToken(TenantId tenantId, String resetToken); + UserCredentials findUserCredentialsByResetToken(TenantId tenantId, String resetToken); - UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials); + UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials); - UserCredentials activateUserCredentials(TenantId tenantId, String activateToken, String password); + UserCredentials activateUserCredentials(TenantId tenantId, String activateToken, String password); - UserCredentials requestPasswordReset(TenantId tenantId, String email); + UserCredentials requestPasswordReset(TenantId tenantId, String email); UserCredentials requestExpiredPasswordReset(TenantId tenantId, UserCredentialsId userCredentialsId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index 2e8844701c..f05e7a1453 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -77,7 +77,7 @@ public interface AlarmDao extends Dao { PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); - List findAlarmIdsByAssigneeId(UUID key); + List findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, int limit); void createEntityAlarmRecord(EntityAlarm entityAlarm); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index f36b56ca7a..542b11494a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -385,10 +385,10 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } @Override - public List findAlarmIdsByAssigneeId(UserId userId) { + public List findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, int limit) { log.trace("Executing findAlarmIdsByAssigneeId [{}]", userId); - validateId(userId, "Incorrect alarmId " + userId); - return alarmDao.findAlarmIdsByAssigneeId(userId.getId()); + validateId(userId, "Incorrect userId " + userId); + return alarmDao.findAlarmIdsByAssigneeId(tenantId, userId.getId(), limit); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index b35ca52e79..1afc7a96be 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -316,7 +316,7 @@ public interface AlarmRepository extends JpaRepository { AlarmInfoEntity findAlarmInfoById(@Param("tenantId") UUID tenantId, @Param("alarmId") UUID alarmId); @Query("SELECT a.id FROM AlarmEntity a WHERE a.assigneeId = :assigneeId") - List findAlarmIdsByAssigneeId(@Param("assigneeId") UUID assigneeId); + List findAlarmIdsByAssigneeId(@Param("assigneeId") UUID assigneeId, Pageable pageable); @Query(value = "SELECT create_or_update_active_alarm(:t_id, :c_id, :a_id, :a_created_ts, :a_o_id, :a_o_type, :a_type, :a_severity, " + ":a_start_ts, :a_end_ts, :a_details, :a_propagate, :a_propagate_to_owner, " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index ed25595442..0a7de4c5e8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -66,7 +66,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; /** * Created by Valerii Sosliuk on 5/19/2017. @@ -287,8 +286,9 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } @Override - public List findAlarmIdsByAssigneeId(UUID key) { - List assignedAlarmIds = alarmRepository.findAlarmIdsByAssigneeId(key); + public List findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, int limit) { + log.debug("[{}] findAlarmIdsByAssigneeId [{}] limit {}", tenantId, userId, limit); + List assignedAlarmIds = alarmRepository.findAlarmIdsByAssigneeId(userId, PageRequest.of(0, limit)); return DaoUtil.fromUUIDs(assignedAlarmIds, AlarmId::new); } From f722ad0757628db09db39d7d19c291a96bb0cd1b Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 16 Aug 2023 10:52:15 +0300 Subject: [PATCH 17/51] Updated test with HouseKeeper service --- .../service/entitiy/alarm/DefaultTbAlarmServiceTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java index 229ea5d9f9..19b8c0bc34 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.edge.EdgeService; +import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; @@ -74,6 +75,8 @@ public class DefaultTbAlarmServiceTest { protected TbClusterService tbClusterService; @MockBean private EntitiesVersionControlService vcService; + @MockBean + protected HouseKeeperService houseKeeperService; @SpyBean DefaultTbAlarmService service; From 35b86999b1338a0795ad470d98ac463e76389639 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 16 Aug 2023 11:18:31 +0300 Subject: [PATCH 18/51] Added timestamp to entity deleted event, to have correct assign ts in alarms after unassignment --- .../server/service/entitiy/alarm/DefaultTbAlarmService.java | 6 +++--- .../server/service/entitiy/alarm/TbAlarmService.java | 2 +- .../housekeeper/InMemoryHouseKeeperServiceService.java | 4 ++-- .../server/dao/housekeeper/HouseKeeperService.java | 2 +- .../server/dao/eventsourcing/DeleteEntityEvent.java | 3 +++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 65302222fc..e250cca7bc 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -225,14 +225,14 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public List unassignDeletedUserAlarms(TenantId tenantId, User user) { + public List unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs) { List totalAlarmIds = new ArrayList<>(); List alarmIds; do { alarmIds = alarmService.findAlarmIdsByAssigneeId(tenantId, user.getId(), 100); for (AlarmId alarmId : alarmIds) { log.trace("[{}] Unassigning alarm {} userId {}", tenantId, alarmId.getId(), user.getId().getId()); - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, System.currentTimeMillis()); + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, unassignTs); Alarm alarm = result.getAlarm(); if (!result.isSuccessful()) { continue; @@ -268,7 +268,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb log.trace("[{}] DeleteEntityEvent handler: {}", event.getTenantId(), event); EntityId entityId = event.getEntityId(); if (EntityType.USER.equals(entityId.getEntityType())) { - housekeeper.unassignDeletedUserAlarms(event.getTenantId(), (User) event.getEntity()); + housekeeper.unassignDeletedUserAlarms(event.getTenantId(), (User) event.getEntity(), event.getTs()); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index c5eb6714ef..24af55f38b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -41,7 +41,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; - List unassignDeletedUserAlarms(TenantId tenantId, User user); + List unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs); Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java index ad3bff921e..1e4d23ac15 100644 --- a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java @@ -66,10 +66,10 @@ public class InMemoryHouseKeeperServiceService implements HouseKeeperService { } @Override - public ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user) { + public ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs) { log.debug("[{}][{}] unassignDeletedUserAlarms submitting, pending queue size: {} ", tenantId, user.getId().getId(), queueSize.get()); queueSize.incrementAndGet(); - ListenableFuture> future = executor.submit(() -> alarmService.unassignDeletedUserAlarms(tenantId, user)); + ListenableFuture> future = executor.submit(() -> alarmService.unassignDeletedUserAlarms(tenantId, user, unassignTs)); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(List alarmIds) { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java index 41f6136c90..62f53e0f41 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/housekeeper/HouseKeeperService.java @@ -24,6 +24,6 @@ import java.util.List; public interface HouseKeeperService { - ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user); + ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java index 6277b7910b..7d0499e8aa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java @@ -28,4 +28,7 @@ public class DeleteEntityEvent { private final EntityId entityId; private final EdgeId edgeId; private final T entity; + + @Builder.Default + private final long ts = System.currentTimeMillis(); } From 1ce4214b79c9e7dd59ecf6ad0692fb854cadef51 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 16 Aug 2023 14:21:22 +0300 Subject: [PATCH 19/51] Added test for DeleteEntityEvent --- .../eventsourcing/DeleteEntityEventTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 dao/src/test/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEventTest.java diff --git a/dao/src/test/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEventTest.java b/dao/src/test/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEventTest.java new file mode 100644 index 0000000000..39d228ceac --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEventTest.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 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.dao.eventsourcing; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.BDDAssertions.byLessThan; + +class DeleteEntityEventTest { + + @Test + void testBuilderDefaultTs() { + assertThat(DeleteEntityEvent.builder().build().getTs()) + .isCloseTo(System.currentTimeMillis(), byLessThan(TimeUnit.MINUTES.toMillis(1))); + + assertThat(DeleteEntityEvent.builder().ts(Long.MIN_VALUE).build().getTs()) + .isEqualTo(Long.MIN_VALUE); + assertThat(DeleteEntityEvent.builder().ts(Long.MAX_VALUE).build().getTs()) + .isEqualTo(Long.MAX_VALUE); + assertThat(DeleteEntityEvent.builder().ts(-1L).build().getTs()) + .isEqualTo(-1L); + assertThat(DeleteEntityEvent.builder().ts(0L).build().getTs()) + .isEqualTo(0L); + + assertThat(DeleteEntityEvent.builder().ts(1692175215000L).build().getTs()) + .isEqualTo(1692175215000L); + } + +} \ No newline at end of file From c4d12c6ba9e0c3ef2822e27271a900c47f80c8f7 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 18 Aug 2023 12:03:27 +0300 Subject: [PATCH 20/51] Refactored DefaultTbAlarmService, added improvements for alarm unassignment on user removing, updated namings and tests. --- .../entitiy/alarm/DefaultTbAlarmService.java | 154 ++++++++---------- .../entitiy/user/DefaultUserService.java | 12 +- .../service/entitiy/user/TbUserService.java | 2 +- .../controller/AlarmControllerTest.java | 92 +++++------ .../server/dao/alarm/AlarmService.java | 4 +- .../server/dao/alarm/AlarmDao.java | 2 +- .../server/dao/alarm/BaseAlarmService.java | 7 +- .../server/dao/sql/alarm/AlarmRepository.java | 5 +- .../server/dao/sql/alarm/JpaAlarmDao.java | 7 +- .../server/dao/user/UserServiceImpl.java | 4 +- 10 files changed, 128 insertions(+), 161 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index e250cca7bc..5d69007884 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.entitiy.alarm; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -38,6 +39,9 @@ import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -108,19 +112,9 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was acknowledged by user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "ACK")) - .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } + String systemComment = String.format("Alarm was acknowledged by user %s", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + addSystemAlarmComment(alarmInfo, user, "ACK", systemComment); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_ACK, user); } else { @@ -142,19 +136,9 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } AlarmInfo alarmInfo = result.getAlarm(); if (result.isCleared()) { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was cleared by user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "CLEAR")) - .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } + String systemComment = String.format("Alarm was cleared by user %s", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + addSystemAlarmComment(alarmInfo, user, "CLEAR", systemComment); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_CLEAR, user); } else { @@ -172,21 +156,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { AlarmAssignee assignee = alarmInfo.getAssignee(); - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was assigned by user %s to user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName(), - (assignee.getFirstName() == null || assignee.getLastName() == null) ? assignee.getEmail() : assignee.getFirstName() + " " + assignee.getLastName())) - .put("userId", user.getId().toString()) - .put("assigneeId", assignee.getId().toString()) - .put("subtype", "ASSIGN")) - .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } + String systemComment = String.format("Alarm was assigned by user %s to user %s", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName(), + (assignee.getFirstName() == null || assignee.getLastName() == null) ? assignee.getEmail() : assignee.getFirstName() + " " + assignee.getLastName()); + addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment, assignee.getId()); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_ASSIGNED, user); } else { @@ -203,19 +176,9 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarm.getId()) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned by user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "ASSIGN")) - .build(); - try { - alarmCommentService.saveAlarmComment(alarm, alarmComment, user); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } + String systemComment = String.format("Alarm was unassigned by user %s", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_UNASSIGNED, user); } else { @@ -227,39 +190,17 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Override public List unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs) { List totalAlarmIds = new ArrayList<>(); - List alarmIds; - do { - alarmIds = alarmService.findAlarmIdsByAssigneeId(tenantId, user.getId(), 100); - for (AlarmId alarmId : alarmIds) { - log.trace("[{}] Unassigning alarm {} userId {}", tenantId, alarmId.getId(), user.getId().getId()); - AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, unassignTs); - Alarm alarm = result.getAlarm(); - if (!result.isSuccessful()) { - continue; - } - if (result.isModified()) { - try { - AlarmComment alarmComment = AlarmComment.builder() - .alarmId(alarmId) - .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode() - .put("text", String.format("Alarm was unassigned because user with id %s - was deleted", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) - .put("userId", user.getId().toString()) - .put("subtype", "ASSIGN")) - .build(); - alarmCommentService.saveAlarmComment(alarm, alarmComment, null); - } catch (ThingsboardException e) { - log.error("Failed to save alarm comment", e); - } - notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(), - alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, null); - } - - totalAlarmIds.addAll(alarmIds); + PageLink pageLink = new PageLink(100, 0, null, new SortOrder("id", SortOrder.Direction.ASC)); + while (true) { + PageData pageData = alarmService.findAlarmIdsByAssigneeId(user.getTenantId(), user.getId(), pageLink); + List alarmIds = pageData.getData(); + if (alarmIds.isEmpty()) { + break; } + processAlarmsUnassignment(tenantId, user, alarmIds, unassignTs); + totalAlarmIds.addAll(alarmIds); + pageLink = pageLink.nextPageLink(); } - while (!alarmIds.isEmpty()); return totalAlarmIds; } @@ -283,4 +224,47 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb private static long getOrDefault(long ts) { return ts > 0 ? ts : System.currentTimeMillis(); } + + private void processAlarmsUnassignment(TenantId tenantId, User user, List alarmIds, long unassignTs) { + for (AlarmId alarmId : alarmIds) { + log.trace("[{}] Unassigning alarm {} userId {}", tenantId, alarmId, user.getId()); + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, unassignTs); + if (!result.isSuccessful()) { + log.error("[{}] Cannot unassign alarm {} userId {}", tenantId, alarmId, user.getId()); + continue; + } + if (result.isModified()) { + String comment = String.format("Alarm was unassigned because user %s - was deleted", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + addSystemAlarmComment(result.getAlarm(), null, "ASSIGN", comment); + notificationEntityService.logEntityAction(result.getAlarm().getTenantId(), result.getAlarm().getOriginator(), result.getAlarm(), result.getAlarm().getCustomerId(), ActionType.ALARM_UNASSIGNED, null); + } + } + } + + private void addSystemAlarmComment(Alarm alarm, User user, String subType, String commentText) { + addSystemAlarmComment(alarm, user, subType, commentText, null); + } + + private void addSystemAlarmComment(Alarm alarm, User user, String subType, String commentText, UserId assigneeId) { + ObjectNode commentNode = JacksonUtil.newObjectNode(); + commentNode.put("text", commentText) + .put("subtype", subType); + if (user != null) { + commentNode.put("userId", user.getId().getId().toString()); + } + if (assigneeId != null) { + commentNode.put("assigneeId", assigneeId.getId().toString()); + } + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode()) + .build(); + try { + alarmCommentService.saveAlarmComment(alarm, alarmComment, user); + } catch (ThingsboardException e) { + log.error("Failed to save alarm comment", e); + } + } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index cc026e08ad..2c2db7c6c7 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; -import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.servlet.http.HttpServletRequest; @@ -44,7 +43,6 @@ import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATT public class DefaultUserService extends AbstractTbEntityService implements TbUserService { private final UserService userService; - private final TbAlarmService tbAlarmService; private final MailService mailService; private final SystemSecurityService systemSecurityService; @@ -77,16 +75,16 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse } @Override - public void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException { + public void delete(TenantId tenantId, CustomerId customerId, User user, User responsibleUser) throws ThingsboardException { ActionType actionType = ActionType.DELETED; - UserId userId = tbUser.getId(); + UserId userId = user.getId(); try { - userService.deleteUser(tenantId, tbUser); - notificationEntityService.logEntityAction(tenantId, userId, tbUser, customerId, actionType, user, customerId.toString()); + userService.deleteUser(tenantId, user); + notificationEntityService.logEntityAction(tenantId, userId, user, customerId, actionType, responsibleUser, customerId.toString()); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), - actionType, user, e, userId.toString()); + actionType, responsibleUser, e, userId.toString()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java index 3ef79371d4..0764425116 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java @@ -25,5 +25,5 @@ import javax.servlet.http.HttpServletRequest; public interface TbUserService { User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail, HttpServletRequest request, User user) throws ThingsboardException; - void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException; + void delete(TenantId tenantId, CustomerId customerId, User user, User responsibleUser) throws ThingsboardException; } diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index ea66bcfcc2..7ee9ffb458 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -47,6 +47,7 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; import static org.hamcrest.Matchers.containsString; @@ -565,22 +566,18 @@ public class AlarmControllerTest extends AbstractControllerTest { alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); Assert.assertNotNull(alarm); + AlarmId alarmId = alarm.getId(); - Mockito.reset(tbClusterService, auditLogService); long beforeAssignmentTs = System.currentTimeMillis(); - doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); - Alarm finalAlarm = alarm; - var alarmObj = new Object() { - AlarmInfo foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); - }; - Assert.assertNotNull(alarmObj.foundAlarm); - Assert.assertEquals(savedUser.getId(), alarmObj.foundAlarm.getAssigneeId()); - Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); + doPost("/api/alarm/" + alarmId.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + Alarm foundAlarm = doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class); - beforeAssignmentTs = System.currentTimeMillis(); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); - Mockito.reset(tbClusterService, auditLogService); + beforeAssignmentTs = System.currentTimeMillis(); loginSysAdmin(); @@ -588,14 +585,12 @@ public class AlarmControllerTest extends AbstractControllerTest { loginDifferentTenant(); - Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> { - alarmObj.foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); - return alarmObj.foundAlarm.getAssigneeId() == null; - }); + foundAlarm = Awaitility.await().atMost(TIMEOUT, TimeUnit.SECONDS) + .until(() -> doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class), Objects::nonNull); - Assert.assertNotNull(alarmObj.foundAlarm); - Assert.assertNull(alarmObj.foundAlarm.getAssigneeId()); - Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test @@ -618,36 +613,27 @@ public class AlarmControllerTest extends AbstractControllerTest { .build(); alarm = doPost("/api/alarm", alarm, Alarm.class); Assert.assertNotNull(alarm); - - alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + AlarmId alarmId = alarm.getId(); + alarm = doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class); Assert.assertNotNull(alarm); - - Mockito.reset(tbClusterService, auditLogService); long beforeAssignmentTs = System.currentTimeMillis(); - doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); - Alarm finalAlarm = alarm; - var alarmObj = new Object() { - AlarmInfo foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); - }; - Assert.assertNotNull(alarmObj.foundAlarm); - Assert.assertEquals(savedUser.getId(), alarmObj.foundAlarm.getAssigneeId()); - Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); + doPost("/api/alarm/" + alarmId.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); - Mockito.reset(tbClusterService, auditLogService); - doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); - Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> { - alarmObj.foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); - return alarmObj.foundAlarm.getAssigneeId() == null; - }); + foundAlarm = Awaitility.await().atMost(TIMEOUT, TimeUnit.SECONDS) + .until(() -> doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class), Objects::nonNull); - Assert.assertNotNull(alarmObj.foundAlarm); - Assert.assertNull(alarmObj.foundAlarm.getAssigneeId()); - Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test @@ -677,21 +663,19 @@ public class AlarmControllerTest extends AbstractControllerTest { .build(); alarm = doPost("/api/alarm", alarm, Alarm.class); Assert.assertNotNull(alarm); + AlarmId alarmId = alarm.getId(); - alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + alarm = doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class); Assert.assertNotNull(alarm); Mockito.reset(tbClusterService, auditLogService); long beforeAssignmentTs = System.currentTimeMillis(); - doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); - Alarm finalAlarm = alarm; - var alarmObj = new Object() { - AlarmInfo foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); - }; - Assert.assertNotNull(alarmObj.foundAlarm); - Assert.assertEquals(savedUser.getId(), alarmObj.foundAlarm.getAssigneeId()); - Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); + doPost("/api/alarm/" + alarmId.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); @@ -699,14 +683,12 @@ public class AlarmControllerTest extends AbstractControllerTest { doDelete("/api/customer/" + differentTenantCustomerId.getId()).andExpect(status().isOk()); - Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> { - alarmObj.foundAlarm = doGet("/api/alarm/info/" + finalAlarm.getId(), AlarmInfo.class); - return alarmObj.foundAlarm.getAssigneeId() == null; - }); + foundAlarm = Awaitility.await().atMost(TIMEOUT, TimeUnit.SECONDS) + .until(() -> doGet("/api/alarm/info/" + alarmId.getId(), AlarmInfo.class), Objects::nonNull); - Assert.assertNotNull(alarmObj.foundAlarm); - Assert.assertNull(alarmObj.foundAlarm.getAssigneeId()); - Assert.assertTrue(alarmObj.foundAlarm.getAssignTs() >= beforeAssignmentTs); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 95e46d66ff..558a65e8f4 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -33,13 +33,13 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.query.AlarmCountQuery; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.Collection; -import java.util.List; public interface AlarmService extends EntityDaoService { @@ -119,7 +119,7 @@ public interface AlarmService extends EntityDaoService { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); - List findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, int limit); + PageData findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, PageLink pageLink); void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index f05e7a1453..93ebc61581 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -77,7 +77,7 @@ public interface AlarmDao extends Dao { PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); - List findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, int limit); + PageData findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, PageLink pageLink); void createEntityAlarmRecord(EntityAlarm entityAlarm); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 542b11494a..b26daba312 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -48,6 +48,7 @@ import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.query.AlarmCountQuery; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -385,10 +386,10 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } @Override - public List findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, int limit) { - log.trace("Executing findAlarmIdsByAssigneeId [{}]", userId); + public PageData findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, PageLink pageLink) { + log.trace("[{}] Executing findAlarmIdsByAssigneeId [{}]", tenantId, userId); validateId(userId, "Incorrect userId " + userId); - return alarmDao.findAlarmIdsByAssigneeId(tenantId, userId.getId(), limit); + return alarmDao.findAlarmIdsByAssigneeId(tenantId, userId.getId(), pageLink); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 1afc7a96be..7db3ea24f8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -21,6 +21,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.sql.AlarmEntity; import org.thingsboard.server.dao.model.sql.AlarmInfoEntity; @@ -315,8 +316,8 @@ public interface AlarmRepository extends JpaRepository { @Query(value = "SELECT a FROM AlarmInfoEntity a WHERE a.tenantId = :tenantId AND a.id = :alarmId") AlarmInfoEntity findAlarmInfoById(@Param("tenantId") UUID tenantId, @Param("alarmId") UUID alarmId); - @Query("SELECT a.id FROM AlarmEntity a WHERE a.assigneeId = :assigneeId") - List findAlarmIdsByAssigneeId(@Param("assigneeId") UUID assigneeId, Pageable pageable); + @Query("SELECT a.id FROM AlarmEntity a WHERE a.tenantId = :tenantId AND a.assigneeId = :assigneeId") + Page findAlarmIdsByAssigneeId(@Param("tenantId") UUID tenantId, @Param("assigneeId") UUID assigneeId, Pageable pageable); @Query(value = "SELECT create_or_update_active_alarm(:t_id, :c_id, :a_id, :a_created_ts, :a_o_id, :a_o_type, :a_type, :a_severity, " + ":a_start_ts, :a_end_ts, :a_details, :a_propagate, :a_propagate_to_owner, " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index 0a7de4c5e8..b6a1d0c92e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -286,10 +286,9 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } @Override - public List findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, int limit) { - log.debug("[{}] findAlarmIdsByAssigneeId [{}] limit {}", tenantId, userId, limit); - List assignedAlarmIds = alarmRepository.findAlarmIdsByAssigneeId(userId, PageRequest.of(0, limit)); - return DaoUtil.fromUUIDs(assignedAlarmIds, AlarmId::new); + public PageData findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, PageLink pageLink) { + return DaoUtil.pageToPageData(alarmRepository.findAlarmIdsByAssigneeId(tenantId.getId(), userId, DaoUtil.toPageable(pageLink))) + .mapData(AlarmId::new); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 295bdc4849..477610f204 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -55,6 +55,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import static org.thingsboard.server.common.data.StringUtils.generateSafeToken; @@ -247,8 +248,9 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic @Override @Transactional public void deleteUser(TenantId tenantId, User user) { + Objects.requireNonNull(user, "User is null"); UserId userId = user.getId(); - log.trace("Executing deleteUser [{}]", userId); + log.trace("[{}] Executing deleteUser [{}]", tenantId, userId); validateId(userId, INCORRECT_USER_ID + userId); UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, userId.getId()); userCredentialsDao.removeById(tenantId, userCredentials.getUuidId()); From 4bfe4395f60ed221cbe1751094ec9628cf3a13b1 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 18 Aug 2023 12:47:21 +0300 Subject: [PATCH 21/51] Refactored user represantation for system comments in alarms --- .../entitiy/alarm/DefaultTbAlarmService.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 5d69007884..d1e3c19e2e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -112,8 +112,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { - String systemComment = String.format("Alarm was acknowledged by user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + String systemComment = String.format("Alarm was acknowledged by user %s", user.getTitle()); addSystemAlarmComment(alarmInfo, user, "ACK", systemComment); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_ACK, user); @@ -136,8 +135,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } AlarmInfo alarmInfo = result.getAlarm(); if (result.isCleared()) { - String systemComment = String.format("Alarm was cleared by user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + String systemComment = String.format("Alarm was cleared by user %s", user.getTitle()); addSystemAlarmComment(alarmInfo, user, "CLEAR", systemComment); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_CLEAR, user); @@ -156,8 +154,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { AlarmAssignee assignee = alarmInfo.getAssignee(); - String systemComment = String.format("Alarm was assigned by user %s to user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName(), + String systemComment = String.format("Alarm was assigned by user %s to user %s", user.getTitle(), (assignee.getFirstName() == null || assignee.getLastName() == null) ? assignee.getEmail() : assignee.getFirstName() + " " + assignee.getLastName()); addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment, assignee.getId()); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, @@ -176,8 +173,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { - String systemComment = String.format("Alarm was unassigned by user %s", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + String systemComment = String.format("Alarm was unassigned by user %s", user.getTitle()); addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_UNASSIGNED, user); @@ -234,8 +230,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb continue; } if (result.isModified()) { - String comment = String.format("Alarm was unassigned because user %s - was deleted", - (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()); + String comment = String.format("Alarm was unassigned because user %s - was deleted", user.getTitle()); addSystemAlarmComment(result.getAlarm(), null, "ASSIGN", comment); notificationEntityService.logEntityAction(result.getAlarm().getTenantId(), result.getAlarm().getOriginator(), result.getAlarm(), result.getAlarm().getCustomerId(), ActionType.ALARM_UNASSIGNED, null); } From 64e60d43f01744255fbc27620c60f0e657695255 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 18 Aug 2023 14:06:08 +0300 Subject: [PATCH 22/51] Moved event listener to HouseKeeper service and added method to get representation from AlarmAssignee --- .../entitiy/alarm/DefaultTbAlarmService.java | 15 +------------ .../InMemoryHouseKeeperServiceService.java | 13 ++++++++++++ .../common/data/alarm/AlarmAssignee.java | 21 +++++++++++++++++++ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index d1e3c19e2e..0e02d1ccd3 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -20,7 +20,6 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; @@ -36,13 +35,11 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AlarmId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; -import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -154,8 +151,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { AlarmAssignee assignee = alarmInfo.getAssignee(); - String systemComment = String.format("Alarm was assigned by user %s to user %s", user.getTitle(), - (assignee.getFirstName() == null || assignee.getLastName() == null) ? assignee.getEmail() : assignee.getFirstName() + " " + assignee.getLastName()); + String systemComment = String.format("Alarm was assigned by user %s to user %s", user.getTitle(), assignee.getTitle()); addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment, assignee.getId()); notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, alarmInfo.getCustomerId(), ActionType.ALARM_ASSIGNED, user); @@ -200,15 +196,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb return totalAlarmIds; } - @TransactionalEventListener(fallbackExecution = true) - public void handleEvent(DeleteEntityEvent event) { - log.trace("[{}] DeleteEntityEvent handler: {}", event.getTenantId(), event); - EntityId entityId = event.getEntityId(); - if (EntityType.USER.equals(entityId.getEntityType())) { - housekeeper.unassignDeletedUserAlarms(event.getTenantId(), (User) event.getEntity(), event.getTs()); - } - } - @Override public Boolean delete(Alarm alarm, User user) { TenantId tenantId = alarm.getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java index 1e4d23ac15..b281452995 100644 --- a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java @@ -25,10 +25,14 @@ import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; @@ -65,6 +69,15 @@ public class InMemoryHouseKeeperServiceService implements HouseKeeperService { } } + @TransactionalEventListener(fallbackExecution = true) + public void handleEvent(DeleteEntityEvent event) { + log.trace("[{}] DeleteEntityEvent handler: {}", event.getTenantId(), event); + EntityId entityId = event.getEntityId(); + if (EntityType.USER.equals(entityId.getEntityType())) { + unassignDeletedUserAlarms(event.getTenantId(), (User) event.getEntity(), event.getTs()); + } + } + @Override public ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs) { log.debug("[{}][{}] unassignDeletedUserAlarms submitting, pending queue size: {} ", tenantId, user.getId().getId(), queueSize.get()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmAssignee.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmAssignee.java index 20ed7b549c..43680242e5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmAssignee.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmAssignee.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.alarm; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -22,6 +23,8 @@ import org.thingsboard.server.common.data.id.UserId; import java.io.Serializable; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; + @Builder @AllArgsConstructor @Data @@ -34,4 +37,22 @@ public class AlarmAssignee implements Serializable { private final String lastName; private final String email; + @JsonIgnore + public String getTitle() { + String title = ""; + if (isNotEmpty(firstName)) { + title += firstName; + } + if (isNotEmpty(lastName)) { + if (!title.isEmpty()) { + title += " "; + } + title += lastName; + } + if (title.isEmpty()) { + title = email; + } + return title; + } + } From 853dfed14cb46e4b8d0b68f4475ccf2e9e985820 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 18 Aug 2023 14:12:19 +0300 Subject: [PATCH 23/51] Removed unnecessary imports --- .../server/service/entitiy/alarm/DefaultTbAlarmService.java | 4 ---- .../housekeeper/InMemoryHouseKeeperServiceService.java | 2 -- 2 files changed, 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 0e02d1ccd3..91223ef69d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -40,7 +40,6 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; -import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.ArrayList; @@ -54,9 +53,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Autowired protected TbAlarmCommentService alarmCommentService; - @Autowired - private HouseKeeperService housekeeper; - @Override public Alarm save(Alarm alarm, User user) throws ThingsboardException { ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED; diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java index b281452995..4e83aa0060 100644 --- a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java @@ -23,7 +23,6 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -47,7 +46,6 @@ import java.util.concurrent.atomic.AtomicInteger; @Slf4j public class InMemoryHouseKeeperServiceService implements HouseKeeperService { - @Lazy final TbAlarmService alarmService; ListeningExecutorService executor; From 5e9bfa32f5c4850f9c2c9707056696dcb43fe0d4 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 18 Aug 2023 14:26:22 +0300 Subject: [PATCH 24/51] Updated import for Awaitility --- .../org/thingsboard/server/controller/AlarmControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 7ee9ffb458..778a97d690 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; +import org.awaitility.Awaitility; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -29,7 +30,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; -import org.testcontainers.shaded.org.awaitility.Awaitility; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; From 38f255ea0d8f84770b35c99a5b1fe6200a2b34ad Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 18 Aug 2023 14:56:56 +0300 Subject: [PATCH 25/51] Removed not required service mock --- .../service/entitiy/alarm/DefaultTbAlarmServiceTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java index 19b8c0bc34..0318360a91 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.edge.EdgeService; -import org.thingsboard.server.dao.housekeeper.HouseKeeperService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; @@ -75,9 +74,6 @@ public class DefaultTbAlarmServiceTest { protected TbClusterService tbClusterService; @MockBean private EntitiesVersionControlService vcService; - @MockBean - protected HouseKeeperService houseKeeperService; - @SpyBean DefaultTbAlarmService service; From c408eb611af330cbe553526a5e7c8ee51d550e7a Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 13:22:25 +0300 Subject: [PATCH 26/51] Added deprecated and alias fields to widget type rpc msg --- .../edge/rpc/constructor/WidgetTypeMsgConstructor.java | 1 + common/edge-api/src/main/proto/edge.proto | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java index b2b82a34d7..3845fd870e 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java @@ -54,6 +54,7 @@ public class WidgetTypeMsgConstructor { if (widgetTypeDetails.getDescription() != null) { builder.setDescription(widgetTypeDetails.getDescription()); } + builder.setDeprecated(widgetTypeDetails.isDeprecated()); return builder.build(); } diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index e505eb1140..a057bd74a4 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -362,12 +362,14 @@ message WidgetTypeUpdateMsg { int64 idMSB = 2; int64 idLSB = 3; optional string bundleAlias = 4; - optional string fqn = 5; + optional string alias = 5; // deprecated optional string name = 6; optional string descriptorJson = 7; bool isSystem = 8; optional string image = 9; optional string description = 10; + optional string fqn = 11; + bool deprecated = 12; } message AdminSettingsUpdateMsg { From ef29f52abd4050046adfa7465ad1ff94e82c44b2 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 13:40:06 +0300 Subject: [PATCH 27/51] Added image for edge dashboard msg --- .../service/edge/rpc/constructor/DashboardMsgConstructor.java | 3 +++ .../edge/rpc/processor/dashboard/BaseDashboardProcessor.java | 1 + common/edge-api/src/main/proto/edge.proto | 1 + 3 files changed, 5 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java index edfdefb603..87d33ef5f5 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java @@ -37,6 +37,9 @@ public class DashboardMsgConstructor { if (dashboard.getAssignedCustomers() != null) { builder.setAssignedCustomers(JacksonUtil.toString(dashboard.getAssignedCustomers())); } + if (dashboard.getImage() != null) { + builder.setImage(dashboard.getImage()); + } return builder.build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java index b055c03cf7..8d82399046 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java @@ -42,6 +42,7 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { dashboard.setCreatedTime(Uuids.unixTimestamp(dashboardId.getId())); } dashboard.setTitle(dashboardUpdateMsg.getTitle()); + dashboard.setImage(dashboardUpdateMsg.hasImage() ? dashboardUpdateMsg.getImage() : null); dashboard.setConfiguration(JacksonUtil.toJsonNode(dashboardUpdateMsg.getConfiguration())); Set assignedCustomers = null; if (dashboardUpdateMsg.hasAssignedCustomers()) { diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index a057bd74a4..a5158f4638 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -187,6 +187,7 @@ message DashboardUpdateMsg { string title = 6; string configuration = 7; optional string assignedCustomers = 8; + optional string image = 9; } message DeviceUpdateMsg { From 439d3e131adbaa8b0818415ce7a3f508f6049aef Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 15:09:20 +0300 Subject: [PATCH 28/51] Fixed no rule chains text hint for autocomplete rulechain component --- .../rule-chain/rule-chain-autocomplete.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.html b/ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.html index e282d62f49..99926fb673 100644 --- a/ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.html @@ -38,7 +38,7 @@
- device-profile.no-device-profiles-found + rulechain.no-rulechains-text
From c6bba789a44323412cceb204ad5026ed5345f1ef Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 15:39:05 +0300 Subject: [PATCH 29/51] edge profile processors - set default rule chains and dashboards moved to subclasses --- .../asset/AssetProfileEdgeProcessor.java | 19 +++++++++++++++++++ .../asset/BaseAssetProfileProcessor.java | 16 ++++++++++------ .../device/BaseDeviceProfileProcessor.java | 19 ++++++++++--------- .../device/DeviceProfileEdgeProcessor.java | 19 +++++++++++++++++++ 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index 3cae9c5123..f0cae07d62 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -28,6 +28,8 @@ import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.AssetProfileId; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; @@ -129,4 +131,21 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { } return downlinkMsg; } + + @Override + protected void setDefaultRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { + // do nothing on cloud + } + + @Override + protected void setDefaultEdgeRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { + UUID defaultEdgeRuleChainUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultRuleChainIdMSB(), assetProfileUpdateMsg.getDefaultRuleChainIdLSB()); + assetProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainUUID != null ? new RuleChainId(defaultEdgeRuleChainUUID) : null); + } + + @Override + protected void setDefaultDashboardId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { + UUID defaultDashboardUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultDashboardIdMSB(), assetProfileUpdateMsg.getDefaultDashboardIdLSB()); + assetProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); + } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java index 4fe778402f..37cfce2fb8 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java @@ -29,7 +29,7 @@ import java.nio.charset.StandardCharsets; import java.util.UUID; @Slf4j -public class BaseAssetProfileProcessor extends BaseEdgeProcessor { +public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { protected boolean saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) { boolean created = false; @@ -50,11 +50,9 @@ public class BaseAssetProfileProcessor extends BaseEdgeProcessor { assetProfile.setImage(assetProfileUpdateMsg.hasImage() ? new String(assetProfileUpdateMsg.getImage().toByteArray(), StandardCharsets.UTF_8) : null); - UUID defaultRuleChainUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultRuleChainIdMSB(), assetProfileUpdateMsg.getDefaultRuleChainIdLSB()); - assetProfile.setDefaultRuleChainId(defaultRuleChainUUID != null ? new RuleChainId(defaultRuleChainUUID) : null); - - UUID defaultDashboardUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultDashboardIdMSB(), assetProfileUpdateMsg.getDefaultDashboardIdLSB()); - assetProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); + setDefaultRuleChainId(assetProfile, assetProfileUpdateMsg); + setDefaultEdgeRuleChainId(assetProfile, assetProfileUpdateMsg); + setDefaultDashboardId(assetProfile, assetProfileUpdateMsg); assetProfileValidator.validate(assetProfile, AssetProfile::getTenantId); if (created) { @@ -66,4 +64,10 @@ public class BaseAssetProfileProcessor extends BaseEdgeProcessor { } return created; } + + protected abstract void setDefaultRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); + + protected abstract void setDefaultEdgeRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); + + protected abstract void setDefaultDashboardId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java index 662a497528..c4f0021269 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java @@ -24,10 +24,8 @@ import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; -import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.queue.util.DataDecodingEncodingService; @@ -38,7 +36,7 @@ import java.util.Optional; import java.util.UUID; @Slf4j -public class BaseDeviceProfileProcessor extends BaseEdgeProcessor { +public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { @Autowired private DataDecodingEncodingService dataDecodingEncodingService; @@ -72,11 +70,9 @@ public class BaseDeviceProfileProcessor extends BaseEdgeProcessor { dataDecodingEncodingService.decode(deviceProfileUpdateMsg.getProfileDataBytes().toByteArray()); deviceProfile.setProfileData(profileDataOpt.orElse(null)); - UUID defaultRuleChainUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultRuleChainIdMSB(), deviceProfileUpdateMsg.getDefaultRuleChainIdLSB()); - deviceProfile.setDefaultRuleChainId(defaultRuleChainUUID != null ? new RuleChainId(defaultRuleChainUUID) : null); - - UUID defaultDashboardUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultDashboardIdMSB(), deviceProfileUpdateMsg.getDefaultDashboardIdLSB()); - deviceProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); + setDefaultRuleChainId(deviceProfile, deviceProfileUpdateMsg); + setDefaultEdgeRuleChainId(deviceProfile, deviceProfileUpdateMsg); + setDefaultDashboardId(deviceProfile, deviceProfileUpdateMsg); String defaultQueueName = StringUtils.isNotBlank(deviceProfileUpdateMsg.getDefaultQueueName()) ? deviceProfileUpdateMsg.getDefaultQueueName() : null; @@ -88,7 +84,6 @@ public class BaseDeviceProfileProcessor extends BaseEdgeProcessor { UUID softwareUUID = safeGetUUID(deviceProfileUpdateMsg.getSoftwareIdMSB(), deviceProfileUpdateMsg.getSoftwareIdLSB()); deviceProfile.setSoftwareId(softwareUUID != null ? new OtaPackageId(softwareUUID) : null); - deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId); if (created) { deviceProfile.setId(deviceProfileId); @@ -99,4 +94,10 @@ public class BaseDeviceProfileProcessor extends BaseEdgeProcessor { } return created; } + + protected abstract void setDefaultRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); + + protected abstract void setDefaultEdgeRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); + + protected abstract void setDefaultDashboardId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index edaffd6f74..4b7bb74e6e 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -27,7 +27,9 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; +import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; @@ -130,4 +132,21 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { } return downlinkMsg; } + + @Override + protected void setDefaultRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + // do nothing on cloud + } + + @Override + protected void setDefaultEdgeRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + UUID defaultEdgeRuleChainUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultRuleChainIdMSB(), deviceProfileUpdateMsg.getDefaultRuleChainIdLSB()); + deviceProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainUUID != null ? new RuleChainId(defaultEdgeRuleChainUUID) : null); + } + + @Override + protected void setDefaultDashboardId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + UUID defaultDashboardUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultDashboardIdMSB(), deviceProfileUpdateMsg.getDefaultDashboardIdLSB()); + deviceProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); + } } From 2a3fa059156883bcda5bba872d7db9f89fcf42f8 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 15:50:03 +0300 Subject: [PATCH 30/51] edge profile processors - added tenant id to abstact methods --- .../asset/AssetProfileEdgeProcessor.java | 6 +++--- .../asset/BaseAssetProfileProcessor.java | 15 ++++++--------- .../device/BaseDeviceProfileProcessor.java | 12 ++++++------ .../device/DeviceProfileEdgeProcessor.java | 6 +++--- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index f0cae07d62..b7cdc68932 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -133,18 +133,18 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { } @Override - protected void setDefaultRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { + protected void setDefaultRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { // do nothing on cloud } @Override - protected void setDefaultEdgeRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { + protected void setDefaultEdgeRuleChainId(TenantId tenantId,AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { UUID defaultEdgeRuleChainUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultRuleChainIdMSB(), assetProfileUpdateMsg.getDefaultRuleChainIdLSB()); assetProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainUUID != null ? new RuleChainId(defaultEdgeRuleChainUUID) : null); } @Override - protected void setDefaultDashboardId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { + protected void setDefaultDashboardId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) { UUID defaultDashboardUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultDashboardIdMSB(), assetProfileUpdateMsg.getDefaultDashboardIdLSB()); assetProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java index 37cfce2fb8..36034430ba 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java @@ -19,14 +19,11 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.AssetProfileId; -import org.thingsboard.server.common.data.id.DashboardId; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; import java.nio.charset.StandardCharsets; -import java.util.UUID; @Slf4j public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { @@ -50,9 +47,9 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { assetProfile.setImage(assetProfileUpdateMsg.hasImage() ? new String(assetProfileUpdateMsg.getImage().toByteArray(), StandardCharsets.UTF_8) : null); - setDefaultRuleChainId(assetProfile, assetProfileUpdateMsg); - setDefaultEdgeRuleChainId(assetProfile, assetProfileUpdateMsg); - setDefaultDashboardId(assetProfile, assetProfileUpdateMsg); + setDefaultRuleChainId(tenantId, assetProfile, assetProfileUpdateMsg); + setDefaultEdgeRuleChainId(tenantId, assetProfile, assetProfileUpdateMsg); + setDefaultDashboardId(tenantId, assetProfile, assetProfileUpdateMsg); assetProfileValidator.validate(assetProfile, AssetProfile::getTenantId); if (created) { @@ -65,9 +62,9 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { return created; } - protected abstract void setDefaultRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); + protected abstract void setDefaultRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); - protected abstract void setDefaultEdgeRuleChainId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); + protected abstract void setDefaultEdgeRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); - protected abstract void setDefaultDashboardId(AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); + protected abstract void setDefaultDashboardId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java index c4f0021269..ab504f9ff2 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java @@ -70,9 +70,9 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { dataDecodingEncodingService.decode(deviceProfileUpdateMsg.getProfileDataBytes().toByteArray()); deviceProfile.setProfileData(profileDataOpt.orElse(null)); - setDefaultRuleChainId(deviceProfile, deviceProfileUpdateMsg); - setDefaultEdgeRuleChainId(deviceProfile, deviceProfileUpdateMsg); - setDefaultDashboardId(deviceProfile, deviceProfileUpdateMsg); + setDefaultRuleChainId(tenantId, deviceProfile, deviceProfileUpdateMsg); + setDefaultEdgeRuleChainId(tenantId, deviceProfile, deviceProfileUpdateMsg); + setDefaultDashboardId(tenantId, deviceProfile, deviceProfileUpdateMsg); String defaultQueueName = StringUtils.isNotBlank(deviceProfileUpdateMsg.getDefaultQueueName()) ? deviceProfileUpdateMsg.getDefaultQueueName() : null; @@ -95,9 +95,9 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { return created; } - protected abstract void setDefaultRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); + protected abstract void setDefaultRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); - protected abstract void setDefaultEdgeRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); + protected abstract void setDefaultEdgeRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); - protected abstract void setDefaultDashboardId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); + protected abstract void setDefaultDashboardId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index 4b7bb74e6e..3638ff6063 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -134,18 +134,18 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { } @Override - protected void setDefaultRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + protected void setDefaultRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { // do nothing on cloud } @Override - protected void setDefaultEdgeRuleChainId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + protected void setDefaultEdgeRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { UUID defaultEdgeRuleChainUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultRuleChainIdMSB(), deviceProfileUpdateMsg.getDefaultRuleChainIdLSB()); deviceProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainUUID != null ? new RuleChainId(defaultEdgeRuleChainUUID) : null); } @Override - protected void setDefaultDashboardId(DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + protected void setDefaultDashboardId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { UUID defaultDashboardUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultDashboardIdMSB(), deviceProfileUpdateMsg.getDefaultDashboardIdLSB()); deviceProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); } From ceda871739b6e008ce95d7d2d0109f933fa09353 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 15:56:47 +0300 Subject: [PATCH 31/51] dashboard edge processor - move setAssignedCustomers to abstact method --- .../processor/dashboard/BaseDashboardProcessor.java | 11 ++++------- .../processor/dashboard/DashboardEdgeProcessor.java | 13 +++++++++++++ .../server/edge/DeviceProfileEdgeTest.java | 12 ++++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java index 8d82399046..5d589c2cc4 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.edge.rpc.processor.dashboard; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Dashboard; @@ -44,12 +43,8 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { dashboard.setTitle(dashboardUpdateMsg.getTitle()); dashboard.setImage(dashboardUpdateMsg.hasImage() ? dashboardUpdateMsg.getImage() : null); dashboard.setConfiguration(JacksonUtil.toJsonNode(dashboardUpdateMsg.getConfiguration())); - Set assignedCustomers = null; - if (dashboardUpdateMsg.hasAssignedCustomers()) { - assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() { - }); - dashboard.setAssignedCustomers(assignedCustomers); - } + + Set assignedCustomers = setAssignedCustomers(tenantId, dashboard, dashboardUpdateMsg); dashboardValidator.validate(dashboard, Dashboard::getTenantId); if (created) { @@ -68,6 +63,8 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { return created; } + protected abstract Set setAssignedCustomers(TenantId tenantId, Dashboard dashboard, DashboardUpdateMsg dashboardUpdateMsg); + private void unassignCustomersFromDashboard(TenantId tenantId, Dashboard dashboard) { if (dashboard.getAssignedCustomers() != null && !dashboard.getAssignedCustomers().isEmpty()) { for (ShortCustomerInfo assignedCustomer : dashboard.getAssignedCustomers()) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index 59f12ec64b..a41c1f6d99 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -16,6 +16,7 @@ package org.thingsboard.server.service.edge.rpc.processor.dashboard; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -25,6 +26,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EdgeUtils; +import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.CustomerId; @@ -41,6 +43,7 @@ import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; +import java.util.Set; import java.util.UUID; @Component @@ -145,4 +148,14 @@ public class DashboardEdgeProcessor extends BaseDashboardProcessor { } return downlinkMsg; } + + @Override + protected Set setAssignedCustomers(TenantId tenantId, Dashboard dashboard, DashboardUpdateMsg dashboardUpdateMsg) { + Set assignedCustomers = null; + if (dashboardUpdateMsg.hasAssignedCustomers()) { + assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() {}); + dashboard.setAssignedCustomers(assignedCustomers); + } + return assignedCustomers; + } } diff --git a/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java index 4e8664aa97..d43cca9d8c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java @@ -303,21 +303,21 @@ public class DeviceProfileEdgeTest extends AbstractEdgeTest { UplinkResponseMsg latestResponseMsg = edgeImitator.getLatestResponseMsg(); Assert.assertTrue(latestResponseMsg.getSuccess()); - AssetProfile assetProfile = doGet("/api/deviceProfile/" + uuid, AssetProfile.class); - Assert.assertNotNull(assetProfile); - Assert.assertEquals("Device Profile On Edge", assetProfile.getName()); + AssetProfile deviceProfile = doGet("/api/deviceProfile/" + uuid, AssetProfile.class); + Assert.assertNotNull(deviceProfile); + Assert.assertEquals("Device Profile On Edge", deviceProfile.getName()); // delete profile edgeImitator.expectMessageAmount(1); - doDelete("/api/deviceProfile/" + assetProfile.getUuidId()) + doDelete("/api/deviceProfile/" + deviceProfile.getUuidId()) .andExpect(status().isOk()); Assert.assertTrue(edgeImitator.waitForMessages()); AbstractMessage latestMessage = edgeImitator.getLatestMessage(); Assert.assertTrue(latestMessage instanceof DeviceProfileUpdateMsg); DeviceProfileUpdateMsg deviceProfileUpdateMsg = (DeviceProfileUpdateMsg) latestMessage; Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, deviceProfileUpdateMsg.getMsgType()); - Assert.assertEquals(assetProfile.getUuidId().getMostSignificantBits(), deviceProfileUpdateMsg.getIdMSB()); - Assert.assertEquals(assetProfile.getUuidId().getLeastSignificantBits(), deviceProfileUpdateMsg.getIdLSB()); + Assert.assertEquals(deviceProfile.getUuidId().getMostSignificantBits(), deviceProfileUpdateMsg.getIdMSB()); + Assert.assertEquals(deviceProfile.getUuidId().getLeastSignificantBits(), deviceProfileUpdateMsg.getIdLSB()); // cleanup unAssignFromEdgeAndDeleteDashboard(dashboardId); From 6566bbc824b369f41c365e3277bad0729b0244ec Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 16:01:03 +0300 Subject: [PATCH 32/51] DashboardEdgeProcessor - refactoring to remove duplicates --- .../processor/dashboard/BaseDashboardProcessor.java | 10 ++++++++-- .../processor/dashboard/DashboardEdgeProcessor.java | 9 ++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java index 5d589c2cc4..11b5bfc371 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java @@ -16,6 +16,7 @@ package org.thingsboard.server.service.edge.rpc.processor.dashboard; import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Dashboard; @@ -44,7 +45,12 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { dashboard.setImage(dashboardUpdateMsg.hasImage() ? dashboardUpdateMsg.getImage() : null); dashboard.setConfiguration(JacksonUtil.toJsonNode(dashboardUpdateMsg.getConfiguration())); - Set assignedCustomers = setAssignedCustomers(tenantId, dashboard, dashboardUpdateMsg); + Set assignedCustomers = null; + if (dashboardUpdateMsg.hasAssignedCustomers()) { + assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() {}); + assignedCustomers = filterNonExistingCustomers(tenantId, assignedCustomers); + dashboard.setAssignedCustomers(assignedCustomers); + } dashboardValidator.validate(dashboard, Dashboard::getTenantId); if (created) { @@ -63,7 +69,7 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { return created; } - protected abstract Set setAssignedCustomers(TenantId tenantId, Dashboard dashboard, DashboardUpdateMsg dashboardUpdateMsg); + protected abstract Set filterNonExistingCustomers(TenantId tenantId, Set assignedCustomers); private void unassignCustomersFromDashboard(TenantId tenantId, Dashboard dashboard) { if (dashboard.getAssignedCustomers() != null && !dashboard.getAssignedCustomers().isEmpty()) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index a41c1f6d99..277a368f2d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.edge.rpc.processor.dashboard; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -150,12 +149,8 @@ public class DashboardEdgeProcessor extends BaseDashboardProcessor { } @Override - protected Set setAssignedCustomers(TenantId tenantId, Dashboard dashboard, DashboardUpdateMsg dashboardUpdateMsg) { - Set assignedCustomers = null; - if (dashboardUpdateMsg.hasAssignedCustomers()) { - assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() {}); - dashboard.setAssignedCustomers(assignedCustomers); - } + protected Set filterNonExistingCustomers(TenantId tenantId, Set assignedCustomers) { + // do nothing on cloud return assignedCustomers; } } From 87ab3e255ed3267a424801b5b6382df8d46c296b Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 16:03:59 +0300 Subject: [PATCH 33/51] EdgeSyncCursor - fetch dashboards before asset and device profiles because of dependency --- .../org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java index a74a0df18c..487e72b21f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java @@ -61,12 +61,12 @@ public class EdgeSyncCursor { fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId())); } } + fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService())); fetchers.add(new AssetProfilesEdgeEventFetcher(ctx.getAssetProfileService())); fetchers.add(new DevicesEdgeEventFetcher(ctx.getDeviceService())); fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService())); fetchers.add(new EntityViewsEdgeEventFetcher(ctx.getEntityViewService())); - fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); if (fullSync) { fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); From bc7ef38ee6db1c681118ecb01b978eef481da6ef Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 16:45:18 +0300 Subject: [PATCH 34/51] Edge dashboard msg - added isMobileHide and mobileOrder --- .../edge/rpc/constructor/DashboardMsgConstructor.java | 6 +++++- .../rpc/processor/dashboard/BaseDashboardProcessor.java | 3 +++ common/edge-api/src/main/proto/edge.proto | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java index 87d33ef5f5..50c2b46891 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java @@ -33,13 +33,17 @@ public class DashboardMsgConstructor { .setIdMSB(dashboard.getId().getId().getMostSignificantBits()) .setIdLSB(dashboard.getId().getId().getLeastSignificantBits()) .setTitle(dashboard.getTitle()) - .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration())); + .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration())) + .setMobileHide(dashboard.isMobileHide()); if (dashboard.getAssignedCustomers() != null) { builder.setAssignedCustomers(JacksonUtil.toString(dashboard.getAssignedCustomers())); } if (dashboard.getImage() != null) { builder.setImage(dashboard.getImage()); } + if (dashboard.getMobileOrder() != null) { + builder.setMobileOrder(dashboard.getMobileOrder()); + } return builder.build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java index 11b5bfc371..687e14a07d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java @@ -52,6 +52,9 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { dashboard.setAssignedCustomers(assignedCustomers); } + dashboard.setMobileOrder(dashboardUpdateMsg.hasMobileOrder() ? dashboardUpdateMsg.getMobileOrder() : null); + dashboard.setMobileHide(dashboardUpdateMsg.getMobileHide()); + dashboardValidator.validate(dashboard, Dashboard::getTenantId); if (created) { dashboard.setId(dashboardId); diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index a5158f4638..0a5e331225 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -188,6 +188,8 @@ message DashboardUpdateMsg { string configuration = 7; optional string assignedCustomers = 8; optional string image = 9; + optional int32 mobileOrder = 10; + bool mobileHide = 11; } message DeviceUpdateMsg { From 6dee8bdbc2fe1f56377216bd6a70342b49c92523 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 29 Aug 2023 17:21:44 +0300 Subject: [PATCH 35/51] device profile processor - remove set of default --- .../edge/rpc/processor/device/BaseDeviceProfileProcessor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java index ab504f9ff2..15a59121fe 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java @@ -54,7 +54,6 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { } deviceProfile.setName(deviceProfileUpdateMsg.getName()); deviceProfile.setDescription(deviceProfileUpdateMsg.hasDescription() ? deviceProfileUpdateMsg.getDescription() : null); - deviceProfile.setDefault(deviceProfileUpdateMsg.getDefault()); deviceProfile.setType(DeviceProfileType.valueOf(deviceProfileUpdateMsg.getType())); deviceProfile.setTransportType(deviceProfileUpdateMsg.hasTransportType() ? DeviceTransportType.valueOf(deviceProfileUpdateMsg.getTransportType()) : DeviceTransportType.DEFAULT); From b3f78e3e56db5b6e391861f5c0c6cb67613c487d Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 30 Aug 2023 12:12:41 +0300 Subject: [PATCH 36/51] added support for new measurement type (PULSE_CNT) --- .../transport/coap/efento/CoapEfentoTransportResource.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java index 31a57fbaf5..1c0a599082 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/efento/CoapEfentoTransportResource.java @@ -309,6 +309,12 @@ public class CoapEfentoTransportResource extends AbstractCoapTransportResource { CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k)); values.addProperty("ok_alarm_" + channel, data); break; + case PULSE_CNT: + values = valuesMap.computeIfAbsent(startTimestampMillis, k -> + CoapEfentoUtils.setDefaultMeasurements(serialNumber, batteryStatus, measurementPeriod, nextTransmissionAtMillis, signal, k)); + values.addProperty("pulse_cnt_" + channel, (double) (startPoint + sampleOffset)); + startTimestampMillis = startTimestampMillis + measurementPeriodMillis; + break; case NO_SENSOR: case UNRECOGNIZED: log.trace("[{}][{}] Sensor error value! Ignoring.", sessionId, measurementTypeName); From 7cb9ee3302c0e5e95479e7d84232f6297e40e11d Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 31 Aug 2023 13:20:38 +0300 Subject: [PATCH 37/51] Added tenant id to edge processor logging --- .../processor/asset/AssetEdgeProcessor.java | 6 +++--- .../dashboard/DashboardEdgeProcessor.java | 6 +++--- .../processor/device/DeviceEdgeProcessor.java | 18 +++++++++--------- .../entityview/EntityViewEdgeProcessor.java | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java index 3e61a538c5..0c41c7e0a0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java @@ -110,16 +110,16 @@ public class AssetEdgeProcessor extends BaseAssetProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, assetId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", asset); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, asset); } @Override public void onFailure(Throwable t) { - log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", asset, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, asset, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push asset action to rule engine: {}", assetId, DataConstants.ENTITY_CREATED, e); + log.warn("[{}][{}] Failed to push asset action to rule engine: {}", tenantId, assetId, DataConstants.ENTITY_CREATED, e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index 277a368f2d..ae9d7e5c33 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -102,16 +102,16 @@ public class DashboardEdgeProcessor extends BaseDashboardProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, dashboardId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", dashboard); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, dashboard); } @Override public void onFailure(Throwable t) { - log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", dashboard, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, dashboard, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push dashboard action to rule engine: {}", dashboardId, DataConstants.ENTITY_CREATED, e); + log.warn("[{}][{}] Failed to push dashboard action to rule engine: {}", tenantId, dashboardId, DataConstants.ENTITY_CREATED, e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index dfa5705840..95bd292356 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -119,16 +119,16 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", device); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, device); } @Override public void onFailure(Throwable t) { - log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", device, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, device, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, TbMsgType.ENTITY_CREATED.name(), e); + log.warn("[{}][{}] Failed to push device action to rule engine: {}", tenantId, deviceId, TbMsgType.ENTITY_CREATED.name(), e); } } @@ -161,7 +161,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { @Override public void onFailure(Throwable t) { - log.error("Can't process push notification to core [{}]", deviceRpcCallMsg, t); + log.error("[{}] Can't process push notification to core [{}]", tenantId, deviceRpcCallMsg, t); futureToSet.setException(t); } }; @@ -196,18 +196,18 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}", - device, deviceRpcCallMsg); + log.debug("[{}] Successfully send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}", + tenantId, device, deviceRpcCallMsg); } @Override public void onFailure(Throwable t) { - log.debug("Failed to send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}", - device, deviceRpcCallMsg, t); + log.debug("[{}] Failed to send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}", + tenantId, device, deviceRpcCallMsg, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push TO_SERVER_RPC_REQUEST to rule engine. deviceRpcCallMsg {}", deviceId, deviceRpcCallMsg, e); + log.warn("[{}][{}] Failed to push TO_SERVER_RPC_REQUEST to rule engine. deviceRpcCallMsg {}", tenantId, deviceId, deviceRpcCallMsg, e); } return Futures.immediateFuture(null); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java index e78b6b4ff5..be6d333332 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java @@ -108,16 +108,16 @@ public class EntityViewEdgeProcessor extends BaseEntityViewProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, entityViewId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", entityView); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entityView); } @Override public void onFailure(Throwable t) { - log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", entityView, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entityView, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push entity view action to rule engine: {}", entityViewId, DataConstants.ENTITY_CREATED, e); + log.warn("[{}][{}] Failed to push entity view action to rule engine: {}", tenantId, entityViewId, DataConstants.ENTITY_CREATED, e); } } From c933f782fb702466053ebb8907bc2aa59c3f5c17 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 31 Aug 2023 16:44:08 +0300 Subject: [PATCH 38/51] Device profile and asset profile - handle name duplicates from edge --- .../asset/AssetProfileEdgeProcessor.java | 10 +++++++++- .../asset/BaseAssetProfileProcessor.java | 14 ++++++++++++-- .../device/BaseDeviceProfileProcessor.java | 16 +++++++++++++--- .../device/DeviceProfileEdgeProcessor.java | 10 +++++++++- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index b7cdc68932..a40cd64ccd 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DataConstants; @@ -27,6 +28,8 @@ import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -74,11 +77,16 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { } private void saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg, Edge edge) { - boolean created = super.saveOrUpdateAssetProfile(tenantId, assetProfileId, assetProfileUpdateMsg); + Pair resultPair = super.saveOrUpdateAssetProfile(tenantId, assetProfileId, assetProfileUpdateMsg); + Boolean created = resultPair.getFirst(); if (created) { createRelationFromEdge(tenantId, edge.getId(), assetProfileId); pushAssetProfileCreatedEventToRuleEngine(tenantId, edge, assetProfileId); } + Boolean assetProfileNameUpdated = resultPair.getSecond(); + if (assetProfileNameUpdated) { + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET_PROFILE, EdgeEventActionType.UPDATED, assetProfileId, null); + } } private void pushAssetProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetProfileId assetProfileId) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java index 36034430ba..5e35bf0332 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java @@ -17,6 +17,8 @@ package org.thingsboard.server.service.edge.rpc.processor.asset; import com.datastax.oss.driver.api.core.uuid.Uuids; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.util.Pair; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.TenantId; @@ -28,8 +30,9 @@ import java.nio.charset.StandardCharsets; @Slf4j public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { - protected boolean saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) { + protected Pair saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) { boolean created = false; + boolean assetProfileNameUpdated = false; assetCreationLock.lock(); try { AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId); @@ -40,6 +43,13 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { assetProfile.setTenantId(tenantId); assetProfile.setCreatedTime(Uuids.unixTimestamp(assetProfileId.getId())); } + AssetProfile assetProfileByName = assetProfileService.findAssetProfileByName(tenantId, assetProfileName); + if (assetProfileByName != null && !assetProfileByName.getId().equals(assetProfileId)) { + assetProfileName = assetProfileName + "_" + StringUtils.randomAlphabetic(15); + log.warn("Asset profile with name {} already exists. Renaming asset profile name to {}", + assetProfileUpdateMsg.getName(), assetProfileName); + assetProfileNameUpdated = true; + } assetProfile.setName(assetProfileName); assetProfile.setDefault(assetProfileUpdateMsg.getDefault()); assetProfile.setDefaultQueueName(assetProfileUpdateMsg.hasDefaultQueueName() ? assetProfileUpdateMsg.getDefaultQueueName() : null); @@ -59,7 +69,7 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { } finally { assetCreationLock.unlock(); } - return created; + return Pair.of(created, assetProfileNameUpdated); } protected abstract void setDefaultRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java index 15a59121fe..324cf14584 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.device; import com.datastax.oss.driver.api.core.uuid.Uuids; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.util.Pair; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; @@ -41,18 +42,27 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { @Autowired private DataDecodingEncodingService dataDecodingEncodingService; - protected boolean saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { + protected Pair saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { boolean created = false; + boolean deviceProfileNameUpdated = false; deviceCreationLock.lock(); try { DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); + String deviceProfileName = deviceProfileUpdateMsg.getName(); if (deviceProfile == null) { created = true; deviceProfile = new DeviceProfile(); deviceProfile.setTenantId(tenantId); deviceProfile.setCreatedTime(Uuids.unixTimestamp(deviceProfileId.getId())); } - deviceProfile.setName(deviceProfileUpdateMsg.getName()); + DeviceProfile deviceProfileByName = deviceProfileService.findDeviceProfileByName(tenantId, deviceProfileName); + if (deviceProfileByName != null && !deviceProfileByName.getId().equals(deviceProfileId)) { + deviceProfileName = deviceProfileName + "_" + StringUtils.randomAlphabetic(15); + log.warn("Device profile with name {} already exists. Renaming device profile name to {}", + deviceProfileUpdateMsg.getName(), deviceProfileName); + deviceProfileNameUpdated = true; + } + deviceProfile.setName(deviceProfileName); deviceProfile.setDescription(deviceProfileUpdateMsg.hasDescription() ? deviceProfileUpdateMsg.getDescription() : null); deviceProfile.setType(DeviceProfileType.valueOf(deviceProfileUpdateMsg.getType())); deviceProfile.setTransportType(deviceProfileUpdateMsg.hasTransportType() @@ -91,7 +101,7 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { } finally { deviceCreationLock.unlock(); } - return created; + return Pair.of(created, deviceProfileNameUpdated); } protected abstract void setDefaultRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index 3638ff6063..470e396cb2 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DataConstants; @@ -27,6 +28,8 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -75,11 +78,16 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { } private void saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg, Edge edge) { - boolean created = super.saveOrUpdateDeviceProfile(tenantId, deviceProfileId, deviceProfileUpdateMsg); + Pair resultPair = super.saveOrUpdateDeviceProfile(tenantId, deviceProfileId, deviceProfileUpdateMsg); + Boolean created = resultPair.getFirst(); if (created) { createRelationFromEdge(tenantId, edge.getId(), deviceProfileId); pushDeviceProfileCreatedEventToRuleEngine(tenantId, edge, deviceProfileId); } + Boolean deviceProfileNameUpdated = resultPair.getSecond(); + if (deviceProfileNameUpdated) { + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE, EdgeEventActionType.UPDATED, deviceProfileId, null); + } } private void pushDeviceProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceProfileId deviceProfileId) { From 0b9f7f0518ae30e1e6551fea3bac13b845f74096 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 1 Sep 2023 16:53:52 +0300 Subject: [PATCH 39/51] Added logs for newly added functionality. Added tenantId into edge logs --- .../edge/DefaultEdgeNotificationService.java | 14 +-- .../service/edge/rpc/EdgeGrpcService.java | 50 ++++++----- .../service/edge/rpc/EdgeGrpcSession.java | 86 ++++++++++--------- .../rpc/constructor/AlarmMsgConstructor.java | 43 +--------- .../constructor/EntityDataMsgConstructor.java | 11 +-- .../AbstractRuleChainMetadataConstructor.java | 2 +- .../fetch/AdminSettingsEdgeEventFetcher.java | 6 +- .../processor/alarm/BaseAlarmProcessor.java | 37 +++++++- .../asset/AssetProfileEdgeProcessor.java | 8 +- .../processor/asset/BaseAssetProcessor.java | 7 +- .../asset/BaseAssetProfileProcessor.java | 7 +- .../processor/device/BaseDeviceProcessor.java | 19 ++-- .../device/BaseDeviceProfileProcessor.java | 9 +- .../device/DeviceProfileEdgeProcessor.java | 9 +- .../rpc/processor/edge/EdgeProcessor.java | 4 +- .../entityview/BaseEntityViewProcessor.java | 4 +- .../relation/BaseRelationProcessor.java | 2 +- .../telemetry/BaseTelemetryProcessor.java | 25 +++--- .../telemetry/TelemetryEdgeProcessor.java | 3 +- .../rpc/sync/DefaultEdgeRequestsService.java | 14 +-- .../server/edge/AssetProfileEdgeTest.java | 54 +++++++++++- .../server/edge/DashboardEdgeTest.java | 10 ++- .../server/edge/DeviceProfileEdgeTest.java | 47 +++++++++- .../server/edge/WidgetEdgeTest.java | 2 + 24 files changed, 291 insertions(+), 182 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java index e19cb80d4c..69852e6c05 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java @@ -155,9 +155,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @Override public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { - log.debug("Pushing notification to edge {}", edgeNotificationMsg); + TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); + log.debug("[{}] Pushing notification to edge {}", tenantId, edgeNotificationMsg); try { - TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); ListenableFuture future; switch (type) { @@ -216,7 +216,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { future = tenantProfileEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; default: - log.warn("Edge event type [{}] is not designed to be pushed to edge", type); + log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); future = Futures.immediateFuture(null); } Futures.addCallback(future, new FutureCallback<>() { @@ -227,16 +227,16 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @Override public void onFailure(Throwable throwable) { - callBackFailure(edgeNotificationMsg, callback, throwable); + callBackFailure(tenantId, edgeNotificationMsg, callback, throwable); } }, dbCallBackExecutor); } catch (Exception e) { - callBackFailure(edgeNotificationMsg, callback, e); + callBackFailure(tenantId, edgeNotificationMsg, callback, e); } } - private void callBackFailure(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) { - log.error("Can't push to edge updates, edgeNotificationMsg [{}]", edgeNotificationMsg, throwable); + private void callBackFailure(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) { + log.error("[{}] Can't push to edge updates, edgeNotificationMsg [{}]", tenantId, edgeNotificationMsg, throwable); callback.onFailure(throwable); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index d002854155..50b80a82f7 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -195,17 +195,17 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i switch (msg.getMsgType()) { case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: EdgeEventUpdateMsg edgeEventUpdateMsg = (EdgeEventUpdateMsg) msg; - log.trace("[{}] onToEdgeSessionMsg [{}]", edgeEventUpdateMsg.getTenantId(), msg); + log.trace("[{}] onToEdgeSessionMsg [{}]", tenantId, msg); onEdgeEvent(tenantId, edgeEventUpdateMsg.getEdgeId()); break; case EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG: ToEdgeSyncRequest toEdgeSyncRequest = (ToEdgeSyncRequest) msg; - log.trace("[{}] toEdgeSyncRequest [{}]", toEdgeSyncRequest.getTenantId(), msg); + log.trace("[{}] toEdgeSyncRequest [{}]", tenantId, msg); startSyncProcess(tenantId, toEdgeSyncRequest.getEdgeId(), toEdgeSyncRequest.getId()); break; case EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG: FromEdgeSyncResponse fromEdgeSyncResponse = (FromEdgeSyncResponse) msg; - log.trace("[{}] fromEdgeSyncResponse [{}]", fromEdgeSyncResponse.getTenantId(), msg); + log.trace("[{}] fromEdgeSyncResponse [{}]", tenantId, msg); processSyncResponse(fromEdgeSyncResponse); break; } @@ -263,7 +263,8 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) { - log.info("[{}] edge [{}] connected successfully.", edgeGrpcSession.getSessionId(), edgeId); + TenantId tenantId = edgeGrpcSession.getEdge().getTenantId(); + log.info("[{}][{}] edge [{}] connected successfully.", tenantId, edgeGrpcSession.getSessionId(), edgeId); sessions.put(edgeId, edgeGrpcSession); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); newEventLock.lock(); @@ -272,10 +273,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } finally { newEventLock.unlock(); } - save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true); + save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true); long lastConnectTs = System.currentTimeMillis(); - save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs); - pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, TbMsgType.CONNECT_EVENT); + save(tenantId, edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs); + pushRuleEngineMessage(tenantId, edgeId, lastConnectTs, TbMsgType.CONNECT_EVENT); cancelScheduleEdgeEventsCheck(edgeId); scheduleEdgeEventsCheck(edgeGrpcSession); } @@ -334,7 +335,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i newEventLock.lock(); try { if (Boolean.TRUE.equals(sessionNewEvents.get(edgeId))) { - log.trace("[{}] Set session new events flag to false", edgeId.getId()); + log.trace("[{}][{}] Set session new events flag to false", tenantId, edgeId.getId()); sessionNewEvents.put(edgeId, false); Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() { @Override @@ -392,9 +393,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } finally { newEventLock.unlock(); } - save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); + TenantId tenantId = toRemove.getEdge().getTenantId(); + save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); long lastDisconnectTs = System.currentTimeMillis(); - save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs); + save(tenantId, edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs); pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, TbMsgType.DISCONNECT_EVENT); cancelScheduleEdgeEventsCheck(edgeId); } else { @@ -402,36 +404,38 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } } - private void save(EdgeId edgeId, String key, long value) { - log.debug("[{}] Updating long edge telemetry [{}] [{}]", edgeId, key, value); + private void save(TenantId tenantId, EdgeId edgeId, String key, long value) { + log.debug("[{}][{}] Updating long edge telemetry [{}] [{}]", tenantId, edgeId, key, value); if (persistToTelemetry) { tsSubService.saveAndNotify( - TenantId.SYS_TENANT_ID, edgeId, + tenantId, edgeId, Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))), - new AttributeSaveCallback(edgeId, key, value)); + new AttributeSaveCallback(tenantId, edgeId, key, value)); } else { - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value)); + tsSubService.saveAttrAndNotify(tenantId, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(tenantId, edgeId, key, value)); } } - private void save(EdgeId edgeId, String key, boolean value) { - log.debug("[{}] Updating boolean edge telemetry [{}] [{}]", edgeId, key, value); + private void save(TenantId tenantId, EdgeId edgeId, String key, boolean value) { + log.debug("[{}][{}] Updating boolean edge telemetry [{}] [{}]", tenantId, edgeId, key, value); if (persistToTelemetry) { tsSubService.saveAndNotify( - TenantId.SYS_TENANT_ID, edgeId, + tenantId, edgeId, Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))), - new AttributeSaveCallback(edgeId, key, value)); + new AttributeSaveCallback(tenantId, edgeId, key, value)); } else { - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value)); + tsSubService.saveAttrAndNotify(tenantId, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(tenantId, edgeId, key, value)); } } private static class AttributeSaveCallback implements FutureCallback { + private final TenantId tenantId; private final EdgeId edgeId; private final String key; private final Object value; - AttributeSaveCallback(EdgeId edgeId, String key, Object value) { + AttributeSaveCallback(TenantId tenantId, EdgeId edgeId, String key, Object value) { + this.tenantId = tenantId; this.edgeId = edgeId; this.key = key; this.value = value; @@ -439,12 +443,12 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i @Override public void onSuccess(@Nullable Void result) { - log.trace("[{}] Successfully updated attribute [{}] with value [{}]", edgeId, key, value); + log.trace("[{}][{}] Successfully updated attribute [{}] with value [{}]", tenantId, edgeId, key, value); } @Override public void onFailure(Throwable t) { - log.warn("[{}] Failed to update attribute [{}] with value [{}]", edgeId, key, value, t); + log.warn("[{}][{}] Failed to update attribute [{}] with value [{}]", tenantId, edgeId, key, value, t); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index d5d73d47e7..37b71ce494 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -105,6 +105,7 @@ public final class EdgeGrpcSession implements Closeable { private EdgeContextComponent ctx; private Edge edge; + private TenantId tenantId; private StreamObserver inputStream; private StreamObserver outputStream; private boolean connected; @@ -148,7 +149,7 @@ public final class EdgeGrpcSession implements Closeable { outputStream.onError(new RuntimeException(responseMsg.getErrorMsg())); } else { if (requestMsg.getConnectRequestMsg().hasMaxInboundMessageSize()) { - log.debug("[{}] Client max inbound message size: {}", sessionId, requestMsg.getConnectRequestMsg().getMaxInboundMessageSize()); + log.debug("[{}][{}] Client max inbound message size: {}", tenantId, sessionId, requestMsg.getConnectRequestMsg().getMaxInboundMessageSize()); clientMaxInboundMessageSize = requestMsg.getConnectRequestMsg().getMaxInboundMessageSize(); } connected = true; @@ -179,13 +180,13 @@ public final class EdgeGrpcSession implements Closeable { @Override public void onError(Throwable t) { - log.error("[{}] Stream was terminated due to error:", sessionId, t); + log.error("[{}][{}] Stream was terminated due to error:", tenantId, sessionId, t); closeSession(); } @Override public void onCompleted() { - log.info("[{}] Stream was closed and completed successfully!", sessionId); + log.info("[{}][{}] Stream was closed and completed successfully!", tenantId, sessionId); closeSession(); } @@ -206,7 +207,7 @@ public final class EdgeGrpcSession implements Closeable { } public void startSyncProcess(boolean fullSync) { - log.trace("[{}][{}][{}] Staring edge sync process", edge.getTenantId(), edge.getId(), this.sessionId); + log.trace("[{}][{}][{}] Staring edge sync process", this.tenantId, edge.getId(), this.sessionId); syncCompleted = false; interruptGeneralProcessingOnSync(); doSync(new EdgeSyncCursor(ctx, edge, fullSync)); @@ -216,7 +217,7 @@ public final class EdgeGrpcSession implements Closeable { if (cursor.hasNext()) { EdgeEventFetcher next = cursor.getNext(); log.info("[{}][{}] starting sync process, cursor current idx = {}, class = {}", - edge.getTenantId(), edge.getId(), cursor.getCurrentIdx(), next.getClass().getSimpleName()); + this.tenantId, edge.getId(), cursor.getCurrentIdx(), next.getClass().getSimpleName()); ListenableFuture> future = startProcessingEdgeEvents(next); Futures.addCallback(future, new FutureCallback<>() { @Override @@ -226,7 +227,7 @@ public final class EdgeGrpcSession implements Closeable { @Override public void onFailure(Throwable t) { - log.error("[{}][{}] Exception during sync process", edge.getTenantId(), edge.getId(), t); + log.error("[{}][{}] Exception during sync process", tenantId, edge.getId(), t); } }, ctx.getGrpcCallbackExecutorService()); } else { @@ -243,7 +244,7 @@ public final class EdgeGrpcSession implements Closeable { @Override public void onFailure(Throwable t) { - log.error("[{}][{}] Exception during sending sync complete", edge.getTenantId(), edge.getId(), t); + log.error("[{}][{}] Exception during sending sync complete", tenantId, edge.getId(), t); } }, ctx.getGrpcCallbackExecutorService()); } @@ -279,39 +280,40 @@ public final class EdgeGrpcSession implements Closeable { try { if (msg.getSuccess()) { sessionState.getPendingMsgsMap().remove(msg.getDownlinkMsgId()); - log.debug("[{}] Msg has been processed successfully!Msd Id: [{}], Msg: {}", edge.getRoutingKey(), msg.getDownlinkMsgId(), msg); + log.debug("[{}][{}] Msg has been processed successfully!Msd Id: [{}], Msg: {}", this.tenantId, edge.getRoutingKey(), msg.getDownlinkMsgId(), msg); } else { - log.error("[{}] Msg processing failed! Msd Id: [{}], Error msg: {}", edge.getRoutingKey(), msg.getDownlinkMsgId(), msg.getErrorMsg()); + log.error("[{}][{}] Msg processing failed! Msd Id: [{}], Error msg: {}", this.tenantId, edge.getRoutingKey(), msg.getDownlinkMsgId(), msg.getErrorMsg()); } if (sessionState.getPendingMsgsMap().isEmpty()) { - log.debug("[{}] Pending msgs map is empty. Stopping current iteration", edge.getRoutingKey()); + log.debug("[{}][{}] Pending msgs map is empty. Stopping current iteration", this.tenantId, edge.getRoutingKey()); stopCurrentSendDownlinkMsgsTask(false); } } catch (Exception e) { - log.error("[{}] Can't process downlink response message [{}]", this.sessionId, msg, e); + log.error("[{}][{}] Can't process downlink response message [{}]", this.tenantId, this.sessionId, msg, e); } } private void sendDownlinkMsg(ResponseMsg downlinkMsg) { - log.trace("[{}] Sending downlink msg [{}]", this.sessionId, downlinkMsg); + log.trace("[{}][{}] Sending downlink msg [{}]", this.tenantId, this.sessionId, downlinkMsg); if (isConnected()) { downlinkMsgLock.lock(); try { outputStream.onNext(downlinkMsg); } catch (Exception e) { - log.error("[{}] Failed to send downlink message [{}]", this.sessionId, downlinkMsg, e); + log.error("[{}][{}] Failed to send downlink message [{}]", this.tenantId, this.sessionId, downlinkMsg, e); connected = false; sessionCloseListener.accept(edge.getId(), sessionId); } finally { downlinkMsgLock.unlock(); } - log.trace("[{}] Response msg successfully sent [{}]", this.sessionId, downlinkMsg); + log.trace("[{}][{}] Response msg successfully sent [{}]", this.tenantId, this.sessionId, downlinkMsg); } } void onConfigurationUpdate(Edge edge) { log.debug("[{}] onConfigurationUpdate [{}]", this.sessionId, edge); this.edge = edge; + this.tenantId = edge.getTenantId(); EdgeUpdateMsg edgeConfig = EdgeUpdateMsg.newBuilder() .setConfiguration(ctx.getEdgeMsgConstructor().constructEdgeConfiguration(edge)).build(); ResponseMsg edgeConfigMsg = ResponseMsg.newBuilder() @@ -322,7 +324,7 @@ public final class EdgeGrpcSession implements Closeable { ListenableFuture processEdgeEvents() throws Exception { SettableFuture result = SettableFuture.create(); - log.trace("[{}] starting processing edge events", this.sessionId); + log.trace("[{}][{}] starting processing edge events", this.tenantId, this.sessionId); if (isConnected() && isSyncCompleted()) { Pair startTsAndSeqId = getQueueStartTsAndSeqId().get(); this.previousStartTs = startTsAndSeqId.getFirst(); @@ -342,7 +344,7 @@ public final class EdgeGrpcSession implements Closeable { Futures.addCallback(updateFuture, new FutureCallback<>() { @Override public void onSuccess(@Nullable List list) { - log.debug("[{}] queue offset was updated [{}]", sessionId, newStartTsAndSeqId); + log.debug("[{}][{}] queue offset was updated [{}]", tenantId, sessionId, newStartTsAndSeqId); if (fetcher.isSeqIdNewCycleStarted()) { seqIdEnd = fetcher.getSeqIdEnd(); boolean newEventsAvailable = isNewEdgeEventsAvailable(); @@ -359,24 +361,24 @@ public final class EdgeGrpcSession implements Closeable { @Override public void onFailure(Throwable t) { - log.error("[{}] Failed to update queue offset [{}]", sessionId, newStartTsAndSeqId, t); + log.error("[{}][{}] Failed to update queue offset [{}]", tenantId, sessionId, newStartTsAndSeqId, t); result.setException(t); } }, ctx.getGrpcCallbackExecutorService()); } else { - log.trace("[{}] newStartTsAndSeqId is null. Skipping iteration without db update", sessionId); + log.trace("[{}][{}] newStartTsAndSeqId is null. Skipping iteration without db update", tenantId, sessionId); result.set(null); } } @Override public void onFailure(Throwable t) { - log.error("[{}] Failed to process events", sessionId, t); + log.error("[{}][{}] Failed to process events", tenantId, sessionId, t); result.setException(t); } }, ctx.getGrpcCallbackExecutorService()); } else { - log.trace("[{}] edge is not connected or sync is not completed. Skipping iteration", sessionId); + log.trace("[{}][{}] edge is not connected or sync is not completed. Skipping iteration", tenantId, sessionId); result.set(null); } return result; @@ -393,13 +395,13 @@ public final class EdgeGrpcSession implements Closeable { try { PageData pageData = fetcher.fetchEdgeEvents(edge.getTenantId(), edge, pageLink); if (isConnected() && !pageData.getData().isEmpty()) { - log.trace("[{}] [{}] event(s) are going to be processed.", this.sessionId, pageData.getData().size()); + log.trace("[{}][{}][{}] event(s) are going to be processed.", this.tenantId, this.sessionId, pageData.getData().size()); List downlinkMsgsPack = convertToDownlinkMsgsPack(pageData.getData()); Futures.addCallback(sendDownlinkMsgsPack(downlinkMsgsPack), new FutureCallback<>() { @Override public void onSuccess(@Nullable Boolean isInterrupted) { if (Boolean.TRUE.equals(isInterrupted)) { - log.debug("[{}][{}][{}] Send downlink messages task was interrupted", edge.getTenantId(), edge.getId(), sessionId); + log.debug("[{}][{}][{}] Send downlink messages task was interrupted", tenantId, edge.getId(), sessionId); result.set(null); } else { if (isConnected() && pageData.hasNext()) { @@ -452,14 +454,14 @@ public final class EdgeGrpcSession implements Closeable { if (isConnected() && sessionState.getPendingMsgsMap().values().size() > 0) { List copy = new ArrayList<>(sessionState.getPendingMsgsMap().values()); if (attempt > 1) { - log.warn("[{}] Failed to deliver the batch: {}, attempt: {}", this.sessionId, copy, attempt); + log.warn("[{}][{}] Failed to deliver the batch: {}, attempt: {}", this.tenantId, this.sessionId, copy, attempt); } - log.trace("[{}] [{}] downlink msg(s) are going to be send.", this.sessionId, copy.size()); + log.trace("[{}][{}][{}] downlink msg(s) are going to be send.", this.tenantId, this.sessionId, copy.size()); for (DownlinkMsg downlinkMsg : copy) { if (this.clientMaxInboundMessageSize != 0 && downlinkMsg.getSerializedSize() > this.clientMaxInboundMessageSize) { log.error("[{}][{}][{}] Downlink msg size [{}] exceeds client max inbound message size [{}]. Skipping this message. " + "Please increase value of CLOUD_RPC_MAX_INBOUND_MESSAGE_SIZE env variable on the edge and restart it." + - "Message {}", edge.getTenantId(), edge.getId(), this.sessionId, downlinkMsg.getSerializedSize(), + "Message {}", this.tenantId, edge.getId(), this.sessionId, downlinkMsg.getSerializedSize(), this.clientMaxInboundMessageSize, downlinkMsg); sessionState.getPendingMsgsMap().remove(downlinkMsg.getDownlinkMsgId()); } else { @@ -471,15 +473,15 @@ public final class EdgeGrpcSession implements Closeable { if (attempt < MAX_DOWNLINK_ATTEMPTS) { scheduleDownlinkMsgsPackSend(attempt + 1); } else { - log.warn("[{}] Failed to deliver the batch after {} attempts. Next messages are going to be discarded {}", - this.sessionId, MAX_DOWNLINK_ATTEMPTS, copy); + log.warn("[{}][{}] Failed to deliver the batch after {} attempts. Next messages are going to be discarded {}", + this.tenantId, this.sessionId, MAX_DOWNLINK_ATTEMPTS, copy); stopCurrentSendDownlinkMsgsTask(false); } } else { stopCurrentSendDownlinkMsgsTask(false); } } catch (Exception e) { - log.warn("[{}] Failed to send downlink msgs. Error msg {}", this.sessionId, e.getMessage(), e); + log.warn("[{}][{}] Failed to send downlink msgs. Error msg {}", this.tenantId, this.sessionId, e.getMessage(), e); stopCurrentSendDownlinkMsgsTask(true); } }; @@ -499,7 +501,7 @@ public final class EdgeGrpcSession implements Closeable { private List convertToDownlinkMsgsPack(List edgeEvents) { List result = new ArrayList<>(); for (EdgeEvent edgeEvent : edgeEvents) { - log.trace("[{}][{}] converting edge event to downlink msg [{}]", edge.getTenantId(), this.sessionId, edgeEvent); + log.trace("[{}][{}] converting edge event to downlink msg [{}]", this.tenantId, this.sessionId, edgeEvent); DownlinkMsg downlinkMsg = null; try { switch (edgeEvent.getAction()) { @@ -518,7 +520,7 @@ public final class EdgeGrpcSession implements Closeable { case ASSIGNED_TO_CUSTOMER: case UNASSIGNED_FROM_CUSTOMER: downlinkMsg = convertEntityEventToDownlink(edgeEvent); - log.trace("[{}][{}] entity message processed [{}]", edgeEvent.getTenantId(), this.sessionId, downlinkMsg); + log.trace("[{}][{}] entity message processed [{}]", this.tenantId, this.sessionId, downlinkMsg); break; case ATTRIBUTES_UPDATED: case POST_ATTRIBUTES: @@ -527,10 +529,10 @@ public final class EdgeGrpcSession implements Closeable { downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent); break; default: - log.warn("[{}][{}] Unsupported action type [{}]", edge.getTenantId(), this.sessionId, edgeEvent.getAction()); + log.warn("[{}][{}] Unsupported action type [{}]", this.tenantId, this.sessionId, edgeEvent.getAction()); } } catch (Exception e) { - log.error("[{}][{}] Exception during converting edge event to downlink msg", edge.getTenantId(), this.sessionId, e); + log.error("[{}][{}] Exception during converting edge event to downlink msg", this.tenantId, this.sessionId, e); } if (downlinkMsg != null) { result.add(downlinkMsg); @@ -566,7 +568,7 @@ public final class EdgeGrpcSession implements Closeable { PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), 0L, this.previousStartSeqId == 0 ? null : this.previousStartSeqId - 1, pageLink); return !edgeEvents.getData().isEmpty(); } catch (Exception e) { - log.error("[{}][{}][{}] Failed to execute isSeqIdStartedNewCycle", edge.getTenantId(), edge.getId(), sessionId, e); + log.error("[{}][{}][{}] Failed to execute isSeqIdStartedNewCycle", this.tenantId, edge.getId(), sessionId, e); } return false; } @@ -577,7 +579,7 @@ public final class EdgeGrpcSession implements Closeable { PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), this.newStartSeqId, null, pageLink); return !edgeEvents.getData().isEmpty(); } catch (Exception e) { - log.error("[{}][{}][{}] Failed to execute isNewEdgeEventsAvailable", edge.getTenantId(), edge.getId(), sessionId, e); + log.error("[{}][{}][{}] Failed to execute isNewEdgeEventsAvailable", this.tenantId, edge.getId(), sessionId, e); } return false; } @@ -591,7 +593,7 @@ public final class EdgeGrpcSession implements Closeable { startSeqId = edgeEvents.getData().get(0).getSeqId() - 1; } } catch (Exception e) { - log.error("[{}][{}][{}] Failed to execute findStartSeqIdFromOldestEventIfAny", edge.getTenantId(), edge.getId(), sessionId, e); + log.error("[{}][{}][{}] Failed to execute findStartSeqIdFromOldestEventIfAny", this.tenantId, edge.getId(), sessionId, e); } return startSeqId; } @@ -607,7 +609,7 @@ public final class EdgeGrpcSession implements Closeable { } private DownlinkMsg convertEntityEventToDownlink(EdgeEvent edgeEvent) { - log.trace("Executing convertEntityEventToDownlink, edgeEvent [{}], action [{}]", edgeEvent, edgeEvent.getAction()); + log.trace("[{}] Executing convertEntityEventToDownlink, edgeEvent [{}], action [{}]", this.tenantId, edgeEvent, edgeEvent.getAction()); switch (edgeEvent.getType()) { case EDGE: return ctx.getEdgeProcessor().convertEdgeEventToDownlink(edgeEvent); @@ -650,7 +652,7 @@ public final class EdgeGrpcSession implements Closeable { case TENANT_PROFILE: return ctx.getTenantProfileEdgeProcessor().convertTenantProfileEventToDownlink(edgeEvent); default: - log.warn("Unsupported edge event type [{}]", edgeEvent); + log.warn("[{}] Unsupported edge event type [{}]", this.tenantId, edgeEvent); return null; } } @@ -749,7 +751,7 @@ public final class EdgeGrpcSession implements Closeable { } } } catch (Exception e) { - log.error("[{}] Can't process uplink msg [{}]", this.sessionId, uplinkMsg, e); + log.error("[{}][{}] Can't process uplink msg [{}]", this.tenantId, this.sessionId, uplinkMsg, e); return Futures.immediateFailedFuture(e); } return Futures.allAsList(result); @@ -791,25 +793,25 @@ public final class EdgeGrpcSession implements Closeable { @Override public void close() { - log.debug("[{}] Closing session", sessionId); + log.debug("[{}][{}] Closing session", this.tenantId, sessionId); connected = false; try { outputStream.onCompleted(); } catch (Exception e) { - log.debug("[{}] Failed to close output stream: {}", sessionId, e.getMessage()); + log.debug("[{}][{}] Failed to close output stream: {}", this.tenantId, sessionId, e.getMessage()); } } private void interruptPreviousSendDownlinkMsgsTask() { if (sessionState.getSendDownlinkMsgsFuture() != null && !sessionState.getSendDownlinkMsgsFuture().isDone() || sessionState.getScheduledSendDownlinkTask() != null && !sessionState.getScheduledSendDownlinkTask().isCancelled()) { - log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", edge.getTenantId(), edge.getId(), this.sessionId); + log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", this.tenantId, edge.getId(), this.sessionId); stopCurrentSendDownlinkMsgsTask(true); } } private void interruptGeneralProcessingOnSync() { - log.debug("[{}][{}][{}] Sync process started. General processing interrupted!", edge.getTenantId(), edge.getId(), this.sessionId); + log.debug("[{}][{}][{}] Sync process started. General processing interrupted!", this.tenantId, edge.getId(), this.sessionId); stopCurrentSendDownlinkMsgsTask(true); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java index 447a73e5cf..15d7c27ff6 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java @@ -15,20 +15,9 @@ */ package org.thingsboard.server.service.edge.rpc.constructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.asset.Asset; -import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EntityViewId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -37,37 +26,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @TbCoreComponent public class AlarmMsgConstructor { - @Autowired - private DeviceService deviceService; - - @Autowired - private AssetService assetService; - - @Autowired - private EntityViewService entityViewService; - - public AlarmUpdateMsg constructAlarmUpdatedMsg(TenantId tenantId, UpdateMsgType msgType, Alarm alarm) { - String entityName = null; - switch (alarm.getOriginator().getEntityType()) { - case DEVICE: - Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId())); - if (deviceById != null) { - entityName = deviceById.getName(); - } - break; - case ASSET: - Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId())); - if (assetById != null) { - entityName = assetById.getName(); - } - break; - case ENTITY_VIEW: - EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId())); - if (entityViewById != null) { - entityName = entityViewById.getName(); - } - break; - } + public AlarmUpdateMsg constructAlarmUpdatedMsg(UpdateMsgType msgType, Alarm alarm, String entityName) { AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder() .setMsgType(msgType) .setIdMSB(alarm.getId().getId().getMostSignificantBits()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java index 242a15ba56..47dbad231d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg; import org.thingsboard.server.gen.edge.v1.EntityDataProto; @@ -40,7 +41,7 @@ import java.util.List; @TbCoreComponent public class EntityDataMsgConstructor { - public EntityDataProto constructEntityDataMsg(EntityId entityId, EdgeEventActionType actionType, JsonElement entityData) { + public EntityDataProto constructEntityDataMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType actionType, JsonElement entityData) { EntityDataProto.Builder builder = EntityDataProto.newBuilder() .setEntityIdMSB(entityId.getId().getMostSignificantBits()) .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) @@ -57,7 +58,7 @@ public class EntityDataMsgConstructor { } builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(data.getAsJsonObject("data"), ts)); } catch (Exception e) { - log.warn("[{}] Can't convert to telemetry proto, entityData [{}]", entityId, entityData, e); + log.warn("[{}][{}] Can't convert to telemetry proto, entityData [{}]", tenantId, entityId, entityData, e); } break; case ATTRIBUTES_UPDATED: @@ -67,7 +68,7 @@ public class EntityDataMsgConstructor { builder.setAttributesUpdatedMsg(attributesUpdatedMsg); builder.setPostAttributeScope(getScopeOfDefault(data)); } catch (Exception e) { - log.warn("[{}] Can't convert to AttributesUpdatedMsg proto, entityData [{}]", entityId, entityData, e); + log.warn("[{}][{}] Can't convert to AttributesUpdatedMsg proto, entityData [{}]", tenantId, entityId, entityData, e); } break; case POST_ATTRIBUTES: @@ -77,7 +78,7 @@ public class EntityDataMsgConstructor { builder.setPostAttributesMsg(postAttributesMsg); builder.setPostAttributeScope(getScopeOfDefault(data)); } catch (Exception e) { - log.warn("[{}] Can't convert to PostAttributesMsg, entityData [{}]", entityId, entityData, e); + log.warn("[{}][{}] Can't convert to PostAttributesMsg, entityData [{}]", tenantId, entityId, entityData, e); } break; case ATTRIBUTES_DELETED: @@ -90,7 +91,7 @@ public class EntityDataMsgConstructor { attributeDeleteMsg.build(); builder.setAttributeDeleteMsg(attributeDeleteMsg); } catch (Exception e) { - log.warn("[{}] Can't convert to AttributeDeleteMsg proto, entityData [{}]", entityId, entityData, e); + log.warn("[{}][{}] Can't convert to AttributeDeleteMsg proto, entityData [{}]", tenantId, entityId, entityData, e); } break; } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java index 28c1b1c458..0099d85bcd 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java @@ -51,7 +51,7 @@ public abstract class AbstractRuleChainMetadataConstructor implements RuleChainM builder.setMsgType(msgType); return builder.build(); } catch (JsonProcessingException ex) { - log.error("Can't construct RuleChainMetadataUpdateMsg", ex); + log.error("[{}] Can't construct RuleChainMetadataUpdateMsg", tenantId, ex); } return null; } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java index cefeb4c46a..b9fc1c8c9e 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java @@ -85,7 +85,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, JacksonUtil.OBJECT_MAPPER.valueToTree(tenantMailSettings))); - AdminSettings systemMailTemplates = loadMailTemplates(); + AdminSettings systemMailTemplates = loadMailTemplates(tenantId); result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, JacksonUtil.OBJECT_MAPPER.valueToTree(systemMailTemplates))); @@ -97,7 +97,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { return new PageData<>(result, 1, result.size(), false); } - private AdminSettings loadMailTemplates() throws Exception { + private AdminSettings loadMailTemplates(TenantId tenantId) throws Exception { Map mailTemplates = new HashMap<>(); for (String templatesName : templatesNames) { Template template = freemarkerConfig.getTemplate(templatesName); @@ -107,7 +107,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { if (mailTemplate != null) { mailTemplates.put(name, mailTemplate); } else { - log.error("Can't load mail template from file {}", template.getName()); + log.error("[{}] Can't load mail template from file {}", tenantId, template.getName()); } } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java index fbe141ab32..de072a48e9 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java @@ -20,15 +20,21 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; +import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; @@ -45,7 +51,7 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor { EntityType.valueOf(alarmUpdateMsg.getOriginatorType())); AlarmId alarmId = new AlarmId(new UUID(alarmUpdateMsg.getIdMSB(), alarmUpdateMsg.getIdLSB())); if (originatorId == null) { - log.warn("Originator not found for the alarm msg {}", alarmUpdateMsg); + log.warn("[{}] Originator not found for the alarm msg {}", tenantId, alarmUpdateMsg); return Futures.immediateFuture(null); } try { @@ -129,13 +135,38 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor { case ALARM_CLEAR: Alarm alarm = alarmService.findAlarmById(tenantId, alarmId); if (alarm != null) { - return alarmMsgConstructor.constructAlarmUpdatedMsg(tenantId, msgType, alarm); + return alarmMsgConstructor.constructAlarmUpdatedMsg(msgType, alarm, findOriginatorEntityName(tenantId, alarm)); } break; case DELETED: Alarm deletedAlarm = JacksonUtil.OBJECT_MAPPER.convertValue(body, Alarm.class); - return alarmMsgConstructor.constructAlarmUpdatedMsg(tenantId, msgType, deletedAlarm); + return alarmMsgConstructor.constructAlarmUpdatedMsg(msgType, deletedAlarm, findOriginatorEntityName(tenantId, deletedAlarm)); } return null; } + + private String findOriginatorEntityName(TenantId tenantId, Alarm alarm) { + String entityName = null; + switch (alarm.getOriginator().getEntityType()) { + case DEVICE: + Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId())); + if (deviceById != null) { + entityName = deviceById.getName(); + } + break; + case ASSET: + Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId())); + if (assetById != null) { + entityName = assetById.getName(); + } + break; + case ENTITY_VIEW: + EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId())); + if (entityViewById != null) { + entityName = entityViewById.getName(); + } + break; + } + return entityName; + } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index a40cd64ccd..21865baa09 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -69,7 +69,7 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { return handleUnsupportedMsgType(assetProfileUpdateMsg.getMsgType()); } } catch (DataValidationException e) { - log.warn("Failed to process AssetProfileUpdateMsg from Edge [{}]", assetProfileUpdateMsg, e); + log.warn("[{}] Failed to process AssetProfileUpdateMsg from Edge [{}]", tenantId, assetProfileUpdateMsg, e); return Futures.immediateFailedFuture(e); } finally { edgeSynchronizationManager.getSync().remove(); @@ -98,16 +98,16 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, assetProfileId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", assetProfile); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, assetProfile); } @Override public void onFailure(Throwable t) { - log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", assetProfile, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, assetProfile, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push asset profile action to rule engine: {}", assetProfileId, DataConstants.ENTITY_CREATED, e); + log.warn("[{}][{}] Failed to push asset profile action to rule engine: {}", tenantId, assetProfileId, DataConstants.ENTITY_CREATED, e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java index 5d728cb4e8..f8dcdbd8f6 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java @@ -49,8 +49,8 @@ public abstract class BaseAssetProcessor extends BaseEdgeProcessor { Asset assetByName = assetService.findAssetByTenantIdAndName(tenantId, assetName); if (assetByName != null && !assetByName.getId().equals(assetId)) { assetName = assetName + "_" + StringUtils.randomAlphanumeric(15); - log.warn("Asset with name {} already exists. Renaming asset name to {}", - assetUpdateMsg.getName(), assetName); + log.warn("[{}] Asset with name {} already exists. Renaming asset name to {}", + tenantId, assetUpdateMsg.getName(), assetName); assetNameUpdated = true; } asset.setName(assetName); @@ -69,6 +69,9 @@ public abstract class BaseAssetProcessor extends BaseEdgeProcessor { asset.setId(assetId); } assetService.saveAsset(asset, false); + } catch (Exception e) { + log.error("[{}] Failed to process asset update msg [{}]", tenantId, assetUpdateMsg, e); + throw e; } finally { assetCreationLock.unlock(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java index 5e35bf0332..67c8f8de44 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java @@ -46,8 +46,8 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { AssetProfile assetProfileByName = assetProfileService.findAssetProfileByName(tenantId, assetProfileName); if (assetProfileByName != null && !assetProfileByName.getId().equals(assetProfileId)) { assetProfileName = assetProfileName + "_" + StringUtils.randomAlphabetic(15); - log.warn("Asset profile with name {} already exists. Renaming asset profile name to {}", - assetProfileUpdateMsg.getName(), assetProfileName); + log.warn("[{}] Asset profile with name {} already exists. Renaming asset profile name to {}", + tenantId, assetProfileUpdateMsg.getName(), assetProfileName); assetProfileNameUpdated = true; } assetProfile.setName(assetProfileName); @@ -66,6 +66,9 @@ public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor { assetProfile.setId(assetProfileId); } assetProfileService.saveAssetProfile(assetProfile, false); + } catch (Exception e) { + log.error("[{}] Failed to process asset profile update msg [{}]", tenantId, assetProfileUpdateMsg, e); + throw e; } finally { assetCreationLock.unlock(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java index 580f752ac1..7993eb4fd8 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java @@ -61,8 +61,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { Device deviceByName = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName); if (deviceByName != null && !deviceByName.getId().equals(deviceId)) { deviceName = deviceName + "_" + StringUtils.randomAlphabetic(15); - log.warn("Device with name {} already exists. Renaming device name to {}", - deviceUpdateMsg.getName(), deviceName); + log.warn("[{}] Device with name {} already exists. Renaming device name to {}", + tenantId, deviceUpdateMsg.getName(), deviceName); deviceNameUpdated = true; } device.setName(deviceName); @@ -98,7 +98,10 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); } tbClusterService.onDeviceUpdated(savedDevice, created ? null : device); - } finally { + } catch (Exception e) { + log.error("[{}] Failed to process device update msg [{}]", tenantId, deviceUpdateMsg, e); + throw e; + } finally { deviceCreationLock.unlock(); } return Pair.of(created, deviceNameUpdated); @@ -110,8 +113,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { return dbCallbackExecutorService.submit(() -> { Device device = deviceService.findDeviceById(tenantId, deviceId); if (device != null) { - log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]", - device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue()); + log.debug("[{}] Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]", + tenantId, device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue()); try { edgeSynchronizationManager.getSync().set(true); @@ -122,14 +125,14 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { ? deviceCredentialsUpdateMsg.getCredentialsValue() : null); deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials); } catch (Exception e) { - log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", - device.getName(), deviceCredentialsUpdateMsg, e); + log.error("[{}] Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", + tenantId, device.getName(), deviceCredentialsUpdateMsg, e); throw new RuntimeException(e); } finally { edgeSynchronizationManager.getSync().remove(); } } else { - log.warn("Can't find device by id [{}], deviceCredentialsUpdateMsg [{}]", deviceId, deviceCredentialsUpdateMsg); + log.warn("[{}] Can't find device by id [{}], deviceCredentialsUpdateMsg [{}]", tenantId, deviceId, deviceCredentialsUpdateMsg); } return null; }); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java index 324cf14584..bd35a42e59 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java @@ -58,8 +58,8 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { DeviceProfile deviceProfileByName = deviceProfileService.findDeviceProfileByName(tenantId, deviceProfileName); if (deviceProfileByName != null && !deviceProfileByName.getId().equals(deviceProfileId)) { deviceProfileName = deviceProfileName + "_" + StringUtils.randomAlphabetic(15); - log.warn("Device profile with name {} already exists. Renaming device profile name to {}", - deviceProfileUpdateMsg.getName(), deviceProfileName); + log.warn("[{}] Device profile with name {} already exists. Renaming device profile name to {}", + tenantId, deviceProfileUpdateMsg.getName(), deviceProfileName); deviceProfileNameUpdated = true; } deviceProfile.setName(deviceProfileName); @@ -98,7 +98,10 @@ public abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor { deviceProfile.setId(deviceProfileId); } deviceProfileService.saveDeviceProfile(deviceProfile, false); - } finally { + } catch (Exception e) { + log.error("[{}] Failed to process device profile update msg [{}]", tenantId, deviceProfileUpdateMsg, e); + throw e; + } finally { deviceCreationLock.unlock(); } return Pair.of(created, deviceProfileNameUpdated); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index 470e396cb2..fe126afd6d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -52,7 +52,6 @@ import java.util.UUID; @TbCoreComponent public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { - public ListenableFuture processDeviceProfileMsgFromEdge(TenantId tenantId, Edge edge, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { log.trace("[{}] executing processDeviceProfileMsgFromEdge [{}] from edge [{}]", tenantId, deviceProfileUpdateMsg, edge.getName()); DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileUpdateMsg.getIdMSB(), deviceProfileUpdateMsg.getIdLSB())); @@ -70,7 +69,7 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { return handleUnsupportedMsgType(deviceProfileUpdateMsg.getMsgType()); } } catch (DataValidationException e) { - log.warn("Failed to process DeviceProfileUpdateMsg from Edge [{}]", deviceProfileUpdateMsg, e); + log.warn("[{}] Failed to process DeviceProfileUpdateMsg from Edge [{}]", tenantId, deviceProfileUpdateMsg, e); return Futures.immediateFailedFuture(e); } finally { edgeSynchronizationManager.getSync().remove(); @@ -99,16 +98,16 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { tbClusterService.pushMsgToRuleEngine(tenantId, deviceProfileId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", deviceProfile); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, deviceProfile); } @Override public void onFailure(Throwable t) { - log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", deviceProfile, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, deviceProfile, t); } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device profile action to rule engine: {}", deviceProfileId, DataConstants.ENTITY_CREATED, e); + log.warn("[{}][{}] Failed to push device profile action to rule engine: {}", tenantId, deviceProfileId, DataConstants.ENTITY_CREATED, e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java index 123209afc1..b38659c881 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java @@ -85,7 +85,7 @@ public class EdgeProcessor extends BaseEdgeProcessor { do { pageData = userService.findCustomerUsers(tenantId, customerId, pageLink); if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { - log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size()); + log.trace("[{}][{}][{}] user(s) are going to be added to edge.", tenantId, edge.getId(), pageData.getData().size()); for (User user : pageData.getData()) { futures.add(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null)); } @@ -108,7 +108,7 @@ public class EdgeProcessor extends BaseEdgeProcessor { return Futures.immediateFuture(null); } } catch (Exception e) { - log.error("Exception during processing edge event", e); + log.error("[{}] Exception during processing edge event", tenantId, e); return Futures.immediateFailedFuture(e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java index 509b2e5196..cca0057707 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java @@ -49,8 +49,8 @@ public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor { EntityView entityViewByName = entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName); if (entityViewByName != null && !entityViewByName.getId().equals(entityViewId)) { entityViewName = entityViewName + "_" + StringUtils.randomAlphanumeric(15); - log.warn("Entity view with name {} already exists. Renaming entity view name to {}", - entityViewUpdateMsg.getName(), entityViewName); + log.warn("[{}] Entity view with name {} already exists. Renaming entity view name to {}", + tenantId, entityViewUpdateMsg.getName(), entityViewName); entityViewNameUpdated = true; } entityView.setName(entityViewName); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java index 9038cc9c33..f7be0cf1f4 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java @@ -59,7 +59,7 @@ public abstract class BaseRelationProcessor extends BaseEdgeProcessor { relationService.saveRelation(tenantId, entityRelation); break; } else { - log.warn("Skipping relating update msg because from/to entity doesn't exists on edge, {}", relationUpdateMsg); + log.warn("[{}] Skipping relating update msg because from/to entity doesn't exists on edge, {}", tenantId, relationUpdateMsg); break; } case ENTITY_DELETED_RPC_MESSAGE: diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java index 5942628bf3..c2d172ede0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java @@ -130,7 +130,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { result.add(processAttributeDeleteMsg(tenantId, entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType())); } } else { - log.warn("Skipping telemetry update msg because entity doesn't exists on edge, {}", entityData); + log.warn("[{}] Skipping telemetry update msg because entity doesn't exists on edge, {}", tenantId, entityData); } return result; } @@ -172,7 +172,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { } break; default: - log.debug("Using empty metadata for entityId [{}]", entityId); + log.debug("[{}] Using empty metadata for entityId [{}]", tenantId, entityId); break; } return new ImmutablePair<>(metaData, customerId != null ? customerId : new CustomerId(ModelConstants.NULL_UUID)); @@ -193,7 +193,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onFailure(Throwable t) { - log.error("Can't process post telemetry [{}]", msg, t); + log.error("[{}] Can't process post telemetry [{}]", tenantId, msg, t); futureToSet.setException(t); } }); @@ -207,7 +207,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { if (EntityType.DEVICE.equals(entityId.getEntityType())) { DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())); if (deviceProfile == null) { - log.warn("[{}] Device profile is null!", entityId); + log.warn("[{}][{}] Device profile is null!", tenantId, entityId); } else { ruleChainId = deviceProfile.getDefaultRuleChainId(); queueName = deviceProfile.getDefaultQueueName(); @@ -215,7 +215,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { } else if (EntityType.ASSET.equals(entityId.getEntityType())) { AssetProfile assetProfile = assetProfileCache.get(tenantId, new AssetId(entityId.getId())); if (assetProfile == null) { - log.warn("[{}] Asset profile is null!", entityId); + log.warn("[{}][{}] Asset profile is null!", tenantId, entityId); } else { ruleChainId = assetProfile.getDefaultRuleChainId(); queueName = assetProfile.getDefaultQueueName(); @@ -237,7 +237,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onFailure(Throwable t) { - log.error("Can't process post attributes [{}]", msg, t); + log.error("[{}] Can't process post attributes [{}]", tenantId, msg, t); futureToSet.setException(t); } }); @@ -267,7 +267,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onFailure(Throwable t) { - log.error("Can't process attributes update [{}]", msg, t); + log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t); futureToSet.setException(t); } }); @@ -275,7 +275,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onFailure(Throwable t) { - log.error("Can't process attributes update [{}]", msg, t); + log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t); futureToSet.setException(t); } }); @@ -300,7 +300,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onFailure(Throwable t) { - log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t); + log.error("[{}] Can't process attribute delete msg [{}]", tenantId, attributeDeleteMsg, t); futureToSet.setException(t); } }); @@ -311,7 +311,8 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { }, dbCallbackExecutorService); } - public EntityDataProto convertTelemetryEventToEntityDataProto(EntityType entityType, + public EntityDataProto convertTelemetryEventToEntityDataProto(TenantId tenantId, + EntityType entityType, UUID entityUUID, EdgeEventActionType actionType, JsonNode body) throws JsonProcessingException { @@ -342,11 +343,11 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { entityId = new EdgeId(entityUUID); break; default: - log.warn("Unsupported edge event type [{}]", entityType); + log.warn("[{}] Unsupported edge event type [{}]", tenantId, entityType); return null; } JsonElement entityData = JsonParser.parseString(JacksonUtil.OBJECT_MAPPER.writeValueAsString(body)); - return entityDataMsgConstructor.constructEntityDataMsg(entityId, actionType, entityData); + return entityDataMsgConstructor.constructEntityDataMsg(tenantId, entityId, actionType, entityData); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java index 66c5596545..861d766638 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java @@ -38,7 +38,8 @@ public class TelemetryEdgeProcessor extends BaseTelemetryProcessor { public DownlinkMsg convertTelemetryEventToDownlink(EdgeEvent edgeEvent) throws JsonProcessingException { EntityType entityType = EntityType.valueOf(edgeEvent.getType().name()); - EntityDataProto entityDataProto = convertTelemetryEventToEntityDataProto(entityType, edgeEvent.getEntityId(), + EntityDataProto entityDataProto = convertTelemetryEventToEntityDataProto( + edgeEvent.getTenantId(), entityType, edgeEvent.getEntityId(), edgeEvent.getAction(), edgeEvent.getBody()); return DownlinkMsg.newBuilder() .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java index 86a97f33db..2483917ce0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java @@ -177,7 +177,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { entityData.put("kv", attributes); entityData.put("scope", scope); JsonNode body = JacksonUtil.OBJECT_MAPPER.valueToTree(entityData); - log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body); + log.debug("[{}] Sending attributes data msg, entityId [{}], attributes [{}]", tenantId, entityId, body); future = saveEdgeEvent(tenantId, edge.getId(), entityType, EdgeEventActionType.ATTRIBUTES_UPDATED, entityId, body); } else { future = Futures.immediateFuture(null); @@ -185,7 +185,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { } return Futures.transformAsync(future, v -> processLatestTimeseriesAndAddToEdgeQueue(tenantId, entityId, edge, entityType), dbCallbackExecutorService); } catch (Exception e) { - String errMsg = String.format("[%s] Failed to save attribute updates to the edge [%s]", edge.getId(), attributesRequestMsg); + String errMsg = String.format("[%s][%s] Failed to save attribute updates to the edge [%s]", tenantId, edge.getId(), attributesRequestMsg); log.error(errMsg, e); return Futures.immediateFailedFuture(new RuntimeException(errMsg, e)); } @@ -239,7 +239,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { if (relationsList != null && !relationsList.isEmpty()) { List> futures = new ArrayList<>(); for (List entityRelations : relationsList) { - log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size()); + log.trace("[{}][{}][{}][{}] relation(s) are going to be pushed to edge.", tenantId, edge.getId(), entityId, entityRelations.size()); for (EntityRelation relation : entityRelations) { try { if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && @@ -252,7 +252,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { JacksonUtil.OBJECT_MAPPER.valueToTree(relation))); } } catch (Exception e) { - String errMsg = String.format("[%s] Exception during loading relation [%s] to edge on sync!", edge.getId(), relation); + String errMsg = String.format("[%s][%s] Exception during loading relation [%s] to edge on sync!", tenantId, edge.getId(), relation); log.error(errMsg, e); futureToSet.setException(new RuntimeException(errMsg, e)); return; @@ -267,7 +267,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @Override public void onFailure(Throwable throwable) { - String errMsg = String.format("[%s] Exception during saving edge events [%s]!", edge.getId(), relationRequestMsg); + String errMsg = String.format("[%s][%s] Exception during saving edge events [%s]!", tenantId, edge.getId(), relationRequestMsg); log.error(errMsg, throwable); futureToSet.setException(new RuntimeException(errMsg, throwable)); } @@ -276,7 +276,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { futureToSet.set(null); } } catch (Exception e) { - log.error("Exception during loading relation(s) to edge on sync!", e); + log.error("[{}] Exception during loading relation(s) to edge on sync!", tenantId, e); futureToSet.setException(e); } } @@ -374,7 +374,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @Override public void onFailure(Throwable t) { - log.error("Exception during loading relation to edge on sync!", t); + log.error("[{}] Exception during loading relation to edge on sync!", tenantId, t); futureToSet.setException(t); } }, dbCallbackExecutorService); diff --git a/application/src/test/java/org/thingsboard/server/edge/AssetProfileEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AssetProfileEdgeTest.java index f77975f0a9..ebf0af1938 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AssetProfileEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AssetProfileEdgeTest.java @@ -20,6 +20,7 @@ import com.google.protobuf.AbstractMessage; import com.google.protobuf.ByteString; import org.junit.Assert; import org.junit.Test; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -30,6 +31,7 @@ import org.thingsboard.server.gen.edge.v1.UplinkMsg; import org.thingsboard.server.gen.edge.v1.UplinkResponseMsg; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.UUID; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -85,7 +87,7 @@ public class AssetProfileEdgeTest extends AbstractEdgeTest { @Test public void testSendAssetProfileToCloud() throws Exception { - RuleChainId ruleChainId = createEdgeRuleChainAndAssignToEdge("Asset Profile Rule Chain"); + RuleChainId edgeRuleChainId = createEdgeRuleChainAndAssignToEdge("Asset Profile Rule Chain"); DashboardId dashboardId = createDashboardAndAssignToEdge("Asset Profile Dashboard"); UUID uuid = Uuids.timeBased(); @@ -96,8 +98,8 @@ public class AssetProfileEdgeTest extends AbstractEdgeTest { assetProfileUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits()); assetProfileUpdateMsgBuilder.setName("Asset Profile On Edge"); assetProfileUpdateMsgBuilder.setDefault(false); - assetProfileUpdateMsgBuilder.setDefaultRuleChainIdMSB(ruleChainId.getId().getMostSignificantBits()); - assetProfileUpdateMsgBuilder.setDefaultRuleChainIdLSB(ruleChainId.getId().getLeastSignificantBits()); + assetProfileUpdateMsgBuilder.setDefaultRuleChainIdMSB(edgeRuleChainId.getId().getMostSignificantBits()); + assetProfileUpdateMsgBuilder.setDefaultRuleChainIdLSB(edgeRuleChainId.getId().getLeastSignificantBits()); assetProfileUpdateMsgBuilder.setDefaultDashboardIdMSB(dashboardId.getId().getMostSignificantBits()); assetProfileUpdateMsgBuilder.setDefaultDashboardIdLSB(dashboardId.getId().getLeastSignificantBits()); assetProfileUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE); @@ -117,6 +119,9 @@ public class AssetProfileEdgeTest extends AbstractEdgeTest { AssetProfile assetProfile = doGet("/api/assetProfile/" + uuid, AssetProfile.class); Assert.assertNotNull(assetProfile); Assert.assertEquals("Asset Profile On Edge", assetProfile.getName()); + Assert.assertEquals(dashboardId, assetProfile.getDefaultDashboardId()); + Assert.assertNull(assetProfile.getDefaultRuleChainId()); + Assert.assertEquals(edgeRuleChainId, assetProfile.getDefaultEdgeRuleChainId()); // delete profile edgeImitator.expectMessageAmount(1); @@ -132,6 +137,47 @@ public class AssetProfileEdgeTest extends AbstractEdgeTest { // cleanup unAssignFromEdgeAndDeleteDashboard(dashboardId); - unAssignFromEdgeAndDeleteRuleChain(ruleChainId); + unAssignFromEdgeAndDeleteRuleChain(edgeRuleChainId); + } + + @Test + public void testSendAssetProfileToCloudWithNameThatAlreadyExistsOnCloud() throws Exception { + String assetProfileOnCloudName = StringUtils.randomAlphanumeric(15); + + edgeImitator.expectMessageAmount(1); + AssetProfile assetProfileOnCloud = this.createAssetProfile(assetProfileOnCloudName); + assetProfileOnCloud = doPost("/api/assetProfile", assetProfileOnCloud, AssetProfile.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + + UUID uuid = Uuids.timeBased(); + + UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); + AssetProfileUpdateMsg.Builder assetProfileUpdateMsgBuilder = AssetProfileUpdateMsg.newBuilder(); + assetProfileUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits()); + assetProfileUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits()); + assetProfileUpdateMsgBuilder.setName(assetProfileOnCloudName); + assetProfileUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE); + uplinkMsgBuilder.addAssetProfileUpdateMsg(assetProfileUpdateMsgBuilder.build()); + + testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder); + + edgeImitator.expectResponsesAmount(1); + edgeImitator.expectMessageAmount(1); + + edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); + + Assert.assertTrue(edgeImitator.waitForResponses()); + Assert.assertTrue(edgeImitator.waitForMessages()); + + Optional assetProfileUpdateMsgOpt = edgeImitator.findMessageByType(AssetProfileUpdateMsg.class); + Assert.assertTrue(assetProfileUpdateMsgOpt.isPresent()); + AssetProfileUpdateMsg latestAssetProfileUpdateMsg = assetProfileUpdateMsgOpt.get(); + Assert.assertNotEquals(assetProfileOnCloudName, latestAssetProfileUpdateMsg.getName()); + + Assert.assertNotEquals(assetProfileOnCloud.getUuidId(), uuid); + + AssetProfile assetProfile = doGet("/api/assetProfile/" + uuid, AssetProfile.class); + Assert.assertNotNull(assetProfile); + Assert.assertNotEquals(assetProfileOnCloudName, assetProfile.getName()); } } diff --git a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java index fd7dfbaafa..2d21d30174 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java @@ -33,7 +33,6 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; -import org.thingsboard.server.gen.edge.v1.UplinkResponseMsg; import java.util.List; import java.util.Optional; @@ -45,12 +44,18 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @DaoSqlTest public class DashboardEdgeTest extends AbstractEdgeTest { + private static final int MOBILE_ORDER = 5; + private static final String IMAGE = "data:image/png;base64,iVBORw0KGgoA"; + @Test public void testDashboards() throws Exception { // create dashboard and assign to edge edgeImitator.expectMessageAmount(1); Dashboard dashboard = new Dashboard(); dashboard.setTitle("Edge Test Dashboard"); + dashboard.setMobileHide(true); + dashboard.setImage(IMAGE); + dashboard.setMobileOrder(MOBILE_ORDER); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); doPost("/api/edge/" + edge.getUuidId() + "/dashboard/" + savedDashboard.getUuidId(), Dashboard.class); @@ -62,6 +67,9 @@ public class DashboardEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedDashboard.getUuidId().getMostSignificantBits(), dashboardUpdateMsg.getIdMSB()); Assert.assertEquals(savedDashboard.getUuidId().getLeastSignificantBits(), dashboardUpdateMsg.getIdLSB()); Assert.assertEquals(savedDashboard.getTitle(), dashboardUpdateMsg.getTitle()); + Assert.assertTrue(dashboardUpdateMsg.getMobileHide()); + Assert.assertEquals(IMAGE, dashboardUpdateMsg.getImage()); + Assert.assertEquals(MOBILE_ORDER, dashboardUpdateMsg.getMobileOrder()); testAutoGeneratedCodeByProtobuf(dashboardUpdateMsg); // update dashboard diff --git a/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java index d43cca9d8c..9d48824bed 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DeviceProfileEdgeTest.java @@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackageInfo; -import org.thingsboard.server.common.data.asset.AssetProfile; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.data.PowerMode; import org.thingsboard.server.common.data.device.data.PowerSavingConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; @@ -303,7 +303,7 @@ public class DeviceProfileEdgeTest extends AbstractEdgeTest { UplinkResponseMsg latestResponseMsg = edgeImitator.getLatestResponseMsg(); Assert.assertTrue(latestResponseMsg.getSuccess()); - AssetProfile deviceProfile = doGet("/api/deviceProfile/" + uuid, AssetProfile.class); + DeviceProfile deviceProfile = doGet("/api/deviceProfile/" + uuid, DeviceProfile.class); Assert.assertNotNull(deviceProfile); Assert.assertEquals("Device Profile On Edge", deviceProfile.getName()); @@ -412,4 +412,47 @@ public class DeviceProfileEdgeTest extends AbstractEdgeTest { transportConfiguration.setCoapDeviceTypeConfiguration(coapDeviceTypeConfiguration); return transportConfiguration; } + + @Test + public void testSendDeviceProfileToCloudWithNameThatAlreadyExistsOnCloud() throws Exception { + String deviceProfileOnCloudName = StringUtils.randomAlphanumeric(15); + + edgeImitator.expectMessageAmount(1); + DeviceProfile deviceProfileOnCloud = this.createDeviceProfile(deviceProfileOnCloudName); + deviceProfileOnCloud = doPost("/api/deviceProfile", deviceProfileOnCloud, DeviceProfile.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + + UUID uuid = Uuids.timeBased(); + + UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); + DeviceProfileUpdateMsg.Builder deviceProfileUpdateMsgBuilder = DeviceProfileUpdateMsg.newBuilder(); + deviceProfileUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits()); + deviceProfileUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits()); + deviceProfileUpdateMsgBuilder.setName(deviceProfileOnCloudName); + deviceProfileUpdateMsgBuilder.setType(DeviceProfileType.DEFAULT.name()); + deviceProfileUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE); + deviceProfileUpdateMsgBuilder.setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfileOnCloud.getProfileData()))); + uplinkMsgBuilder.addDeviceProfileUpdateMsg(deviceProfileUpdateMsgBuilder.build()); + + testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder); + + edgeImitator.expectResponsesAmount(1); + edgeImitator.expectMessageAmount(1); + + edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); + + Assert.assertTrue(edgeImitator.waitForResponses()); + Assert.assertTrue(edgeImitator.waitForMessages()); + + Optional deviceProfileUpdateMsgOpt = edgeImitator.findMessageByType(DeviceProfileUpdateMsg.class); + Assert.assertTrue(deviceProfileUpdateMsgOpt.isPresent()); + DeviceProfileUpdateMsg latestDeviceProfileUpdateMsg = deviceProfileUpdateMsgOpt.get(); + Assert.assertNotEquals(deviceProfileOnCloudName, latestDeviceProfileUpdateMsg.getName()); + + Assert.assertNotEquals(deviceProfileOnCloud.getUuidId(), uuid); + + DeviceProfile deviceProfile = doGet("/api/deviceProfile/" + uuid, DeviceProfile.class); + Assert.assertNotNull(deviceProfile); + Assert.assertNotEquals(deviceProfileOnCloudName, deviceProfile.getName()); + } } diff --git a/application/src/test/java/org/thingsboard/server/edge/WidgetEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/WidgetEdgeTest.java index c4fe89a209..54d85a1cef 100644 --- a/application/src/test/java/org/thingsboard/server/edge/WidgetEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/WidgetEdgeTest.java @@ -58,6 +58,7 @@ public class WidgetEdgeTest extends AbstractEdgeTest { ObjectNode descriptor = JacksonUtil.newObjectNode(); descriptor.put("key", "value"); widgetType.setDescriptor(descriptor); + widgetType.setDeprecated(true); WidgetType savedWidgetType = doPost("/api/widgetType", widgetType, WidgetType.class); Assert.assertTrue(edgeImitator.waitForMessages()); latestMessage = edgeImitator.getLatestMessage(); @@ -68,6 +69,7 @@ public class WidgetEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedWidgetType.getUuidId().getLeastSignificantBits(), widgetTypeUpdateMsg.getIdLSB()); Assert.assertEquals(savedWidgetType.getFqn(), widgetTypeUpdateMsg.getFqn()); Assert.assertEquals(savedWidgetType.getName(), widgetTypeUpdateMsg.getName()); + Assert.assertTrue(widgetTypeUpdateMsg.getDeprecated()); Assert.assertEquals(JacksonUtil.toJsonNode(widgetTypeUpdateMsg.getDescriptorJson()), savedWidgetType.getDescriptor()); // update widget bundle From be6435efd1ce62b839e6fb29ed8dbf4f70ef6502 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 4 Sep 2023 10:37:06 +0300 Subject: [PATCH 40/51] Added DefaultProfilesEdgeEventFetcher --- .../service/edge/rpc/EdgeSyncCursor.java | 2 + .../DefaultProfilesEdgeEventFetcher.java | 62 +++++++++++++++++++ .../server/controller/EdgeControllerTest.java | 6 +- .../server/edge/AbstractEdgeTest.java | 13 ++-- 4 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java index 487e72b21f..ed8eeade7b 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java @@ -25,6 +25,7 @@ import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.CustomerEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher; +import org.thingsboard.server.service.edge.rpc.fetch.DefaultProfilesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.DevicesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.EdgeEventFetcher; @@ -62,6 +63,7 @@ public class EdgeSyncCursor { } } fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); + fetchers.add(new DefaultProfilesEdgeEventFetcher(ctx.getDeviceProfileService(), ctx.getAssetProfileService())); fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService())); fetchers.add(new AssetProfilesEdgeEventFetcher(ctx.getAssetProfileService())); fetchers.add(new DevicesEdgeEventFetcher(ctx.getDeviceService())); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java new file mode 100644 index 0000000000..1b4897dfff --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java @@ -0,0 +1,62 @@ +/** + * Copyright © 2016-2023 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.service.edge.rpc.fetch; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.EdgeUtils; +import org.thingsboard.server.common.data.asset.AssetProfile; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeEvent; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.asset.AssetProfileService; +import org.thingsboard.server.dao.device.DeviceProfileService; + +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@Slf4j +public class DefaultProfilesEdgeEventFetcher implements EdgeEventFetcher { + + private final DeviceProfileService deviceProfileService; + private final AssetProfileService assetProfileService; + + @Override + public PageLink getPageLink(int pageSize) { + return null; + } + + @Override + public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { + List result = new ArrayList<>(); + + DeviceProfile deviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId); + result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE, + EdgeEventActionType.ADDED, deviceProfile.getId(), null)); + + AssetProfile assetProfile = assetProfileService.findDefaultAssetProfile(tenantId); + result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET_PROFILE, + EdgeEventActionType.ADDED, assetProfile.getId(), null)); + + return new PageData<>(result, 1, result.size(), false); + } +} \ No newline at end of file diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java index bdd5f8d352..081ce09ae7 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java @@ -860,7 +860,7 @@ public class EdgeControllerTest extends AbstractControllerTest { EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret()); edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); - edgeImitator.expectMessageAmount(23); + edgeImitator.expectMessageAmount(25); edgeImitator.connect(); assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue(); @@ -873,7 +873,7 @@ public class EdgeControllerTest extends AbstractControllerTest { Assert.assertTrue(popAssetMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Asset 1")); Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty()); - edgeImitator.expectMessageAmount(18); + edgeImitator.expectMessageAmount(20); doPost("/api/edge/sync/" + edge.getId()); assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue(); @@ -903,6 +903,8 @@ public class EdgeControllerTest extends AbstractControllerTest { Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mailTemplates", false)); Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); + Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); + Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test")); Assert.assertTrue(popUserMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, TENANT_ADMIN_EMAIL, Authority.TENANT_ADMIN)); Assert.assertTrue(popCustomerMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Public")); diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index 232b9d7ca5..410348762f 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -129,7 +129,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { installation(); edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); - edgeImitator.expectMessageAmount(24); + edgeImitator.expectMessageAmount(26); edgeImitator.connect(); requestEdgeRuleChainMetadata(); @@ -236,13 +236,15 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { // 4 messages - 4 messages from fetcher - 2 from system level ('mail', 'mailTemplates') and 2 from admin level ('mail', 'mailTemplates') validateAdminSettings(); - // 4 messages + // 5 messages + // - 1 from default profile fetcher // - 2 from device profile fetcher (default and thermostat) // - 1 from device fetcher // - 1 from device controller (thermostat) validateDeviceProfiles(); - // 3 messages + // 4 messages + // - 1 from default profile fetcher // - 1 message from asset profile fetcher // - 1 message from asset fetcher // - 1 message from asset controller @@ -301,11 +303,12 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { private void validateDeviceProfiles() throws Exception { List deviceProfileUpdateMsgList = edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class); + // default msg default device profile from fetcher // default msg device profile from fetcher // thermostat msg from device profile fetcher // thermostat msg from device fetcher // thermostat msg from creation of device - Assert.assertEquals(4, deviceProfileUpdateMsgList.size()); + Assert.assertEquals(5, deviceProfileUpdateMsgList.size()); Optional thermostatProfileUpdateMsgOpt = deviceProfileUpdateMsgList.stream().filter(dfum -> THERMOSTAT_DEVICE_PROFILE_NAME.equals(dfum.getName())).findAny(); Assert.assertTrue(thermostatProfileUpdateMsgOpt.isPresent()); @@ -425,7 +428,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { private void validateAssetProfiles() throws Exception { List assetProfileUpdateMsgs = edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class); - Assert.assertEquals(3, assetProfileUpdateMsgs.size()); + Assert.assertEquals(4, assetProfileUpdateMsgs.size()); AssetProfileUpdateMsg assetProfileUpdateMsg = assetProfileUpdateMsgs.get(0); Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, assetProfileUpdateMsg.getMsgType()); UUID assetProfileUUID = new UUID(assetProfileUpdateMsg.getIdMSB(), assetProfileUpdateMsg.getIdLSB()); From c7b0878ac136d2acf3d640d790e2db631def5bfa Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 4 Sep 2023 11:12:58 +0300 Subject: [PATCH 41/51] Move pushEntityCreatedEventToRuleEngine method to base processor --- .../edge/rpc/processor/BaseEdgeProcessor.java | 30 +++++++++++++---- .../processor/asset/AssetEdgeProcessor.java | 29 ++++------------ .../asset/AssetProfileEdgeProcessor.java | 29 ++++------------ .../dashboard/DashboardEdgeProcessor.java | 29 ++++------------ .../processor/device/DeviceEdgeProcessor.java | 19 +++-------- .../device/DeviceProfileEdgeProcessor.java | 29 ++++------------ .../entityview/EntityViewEdgeProcessor.java | 33 +++++-------------- 7 files changed, 59 insertions(+), 139 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index 239f72dcd6..1715c5212e 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -46,12 +46,15 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetProfileService; @@ -78,6 +81,8 @@ import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.TbQueueCallback; +import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.service.edge.rpc.constructor.AdminSettingsMsgConstructor; @@ -566,18 +571,29 @@ public abstract class BaseEdgeProcessor { relationService.saveRelation(tenantId, relation); } - protected TbMsgMetaData getActionTbMsgMetaData(Edge edge, CustomerId customerId) { - TbMsgMetaData metaData = getTbMsgMetaData(edge); + protected TbMsgMetaData getEdgeActionTbMsgMetaData(Edge edge, CustomerId customerId) { + TbMsgMetaData metaData = new TbMsgMetaData(); + metaData.putValue("edgeId", edge.getId().toString()); + metaData.putValue("edgeName", edge.getName()); if (customerId != null && !customerId.isNullUid()) { metaData.putValue("customerId", customerId.toString()); } return metaData; } - protected TbMsgMetaData getTbMsgMetaData(Edge edge) { - TbMsgMetaData metaData = new TbMsgMetaData(); - metaData.putValue("edgeId", edge.getId().toString()); - metaData.putValue("edgeName", edge.getName()); - return metaData; + protected void pushEntityCreatedEventToRuleEngine(TenantId tenantId, EntityId entityId, CustomerId customerId, + String entity, TbMsgMetaData metaData) { + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, entityId, customerId, metaData, TbMsgDataType.JSON, entity); + tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, new TbQueueCallback() { + @Override + public void onSuccess(TbQueueMsgMetadata metadata) { + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entity); + } + + @Override + public void onFailure(Throwable t) { + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entity, t); + } + }); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java index 0c41c7e0a0..71a39b16f4 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java @@ -15,15 +15,12 @@ */ package org.thingsboard.server.service.edge.rpc.processor.asset; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Pair; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; @@ -35,15 +32,12 @@ import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.asset.BaseAssetService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.queue.TbQueueCallback; -import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.UUID; @@ -104,22 +98,11 @@ public class AssetEdgeProcessor extends BaseAssetProcessor { private void pushAssetCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetId assetId) { try { Asset asset = assetService.findAssetById(tenantId, assetId); - ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(asset); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, assetId, asset.getCustomerId(), - getActionTbMsgMetaData(edge, asset.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); - tbClusterService.pushMsgToRuleEngine(tenantId, assetId, tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, asset); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, asset, t); - } - }); - } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}][{}] Failed to push asset action to rule engine: {}", tenantId, assetId, DataConstants.ENTITY_CREATED, e); + String assetAsString = JacksonUtil.toString(asset); + TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, asset.getCustomerId()); + pushEntityCreatedEventToRuleEngine(tenantId, assetId, asset.getCustomerId(), assetAsString, msgMetaData); + } catch (Exception e) { + log.warn("[{}][{}] Failed to push asset action to rule engine: {}", tenantId, assetId, TbMsgType.ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index 21865baa09..71c231fb6f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -15,15 +15,12 @@ */ package org.thingsboard.server.service.edge.rpc.processor.asset; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Pair; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.Edge; @@ -35,14 +32,11 @@ import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.queue.TbQueueCallback; -import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.UUID; @@ -92,22 +86,11 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { private void pushAssetProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetProfileId assetProfileId) { try { AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId); - ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(assetProfile); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, assetProfileId, getTbMsgMetaData(edge), - TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); - tbClusterService.pushMsgToRuleEngine(tenantId, assetProfileId, tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, assetProfile); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, assetProfile, t); - } - }); - } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}][{}] Failed to push asset profile action to rule engine: {}", tenantId, assetProfileId, DataConstants.ENTITY_CREATED, e); + String assetProfileAsString = JacksonUtil.toString(assetProfile); + TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null); + pushEntityCreatedEventToRuleEngine(tenantId, assetProfileId, null, assetProfileAsString, msgMetaData); + } catch (Exception e) { + log.warn("[{}][{}] Failed to push asset profile action to rule engine: {}", tenantId, assetProfileId, TbMsgType.ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index ae9d7e5c33..40cc6169b5 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -15,15 +15,12 @@ */ package org.thingsboard.server.service.edge.rpc.processor.dashboard; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.edge.Edge; @@ -32,14 +29,11 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.queue.TbQueueCallback; -import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.Set; @@ -96,22 +90,11 @@ public class DashboardEdgeProcessor extends BaseDashboardProcessor { private void pushDashboardCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DashboardId dashboardId) { try { Dashboard dashboard = dashboardService.findDashboardById(tenantId, dashboardId); - ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(dashboard); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, dashboardId, null, - getActionTbMsgMetaData(edge, null), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); - tbClusterService.pushMsgToRuleEngine(tenantId, dashboardId, tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, dashboard); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, dashboard, t); - } - }); - } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}][{}] Failed to push dashboard action to rule engine: {}", tenantId, dashboardId, DataConstants.ENTITY_CREATED, e); + String dashboardAsString = JacksonUtil.toString(dashboard); + TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null); + pushEntityCreatedEventToRuleEngine(tenantId, dashboardId, null, dashboardAsString, msgMetaData); + } catch (Exception e) { + log.warn("[{}][{}] Failed to push dashboard action to rule engine: {}", tenantId, dashboardId, TbMsgType.ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index 95bd292356..cbc8c57e51 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -113,21 +113,10 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceId deviceId) { try { Device device = deviceService.findDeviceById(tenantId, deviceId); - ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, device.getCustomerId(), - getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); - tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, device); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, device, t); - } - }); - } catch (JsonProcessingException | IllegalArgumentException e) { + String deviceAsString = JacksonUtil.toString(device); + TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, device.getCustomerId()); + pushEntityCreatedEventToRuleEngine(tenantId, deviceId, device.getCustomerId(), deviceAsString, msgMetaData); + } catch (Exception e) { log.warn("[{}][{}] Failed to push device action to rule engine: {}", tenantId, deviceId, TbMsgType.ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index fe126afd6d..6feeee625d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -15,15 +15,12 @@ */ package org.thingsboard.server.service.edge.rpc.processor.device; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Pair; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.Edge; @@ -35,14 +32,11 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.queue.TbQueueCallback; -import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.UUID; @@ -92,22 +86,11 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { private void pushDeviceProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceProfileId deviceProfileId) { try { DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); - ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(deviceProfile); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceProfileId, getTbMsgMetaData(edge), - TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); - tbClusterService.pushMsgToRuleEngine(tenantId, deviceProfileId, tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, deviceProfile); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, deviceProfile, t); - } - }); - } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}][{}] Failed to push device profile action to rule engine: {}", tenantId, deviceProfileId, DataConstants.ENTITY_CREATED, e); + String deviceProfileAsString = JacksonUtil.toString(deviceProfile); + TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null); + pushEntityCreatedEventToRuleEngine(tenantId, deviceProfileId, null, deviceProfileAsString, msgMetaData); + } catch (Exception e) { + log.warn("[{}][{}] Failed to push device profile action to rule engine: {}", tenantId, deviceProfileId, TbMsgType.ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java index be6d333332..6e624bce5f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java @@ -15,15 +15,12 @@ */ package org.thingsboard.server.service.edge.rpc.processor.entityview; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Pair; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.edge.Edge; @@ -34,14 +31,11 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.queue.TbQueueCallback; -import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.UUID; @@ -90,7 +84,7 @@ public class EntityViewEdgeProcessor extends BaseEntityViewProcessor { Boolean created = resultPair.getFirst(); if (created) { createRelationFromEdge(tenantId, edge.getId(), entityViewId); - pushAssetCreatedEventToRuleEngine(tenantId, edge, entityViewId); + pushEntityViewCreatedEventToRuleEngine(tenantId, edge, entityViewId); entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edge.getId()); } Boolean assetNameUpdated = resultPair.getSecond(); @@ -99,25 +93,14 @@ public class EntityViewEdgeProcessor extends BaseEntityViewProcessor { } } - private void pushAssetCreatedEventToRuleEngine(TenantId tenantId, Edge edge, EntityViewId entityViewId) { + private void pushEntityViewCreatedEventToRuleEngine(TenantId tenantId, Edge edge, EntityViewId entityViewId) { try { EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId); - ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(entityView); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, entityViewId, entityView.getCustomerId(), - getActionTbMsgMetaData(edge, entityView.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); - tbClusterService.pushMsgToRuleEngine(tenantId, entityViewId, tbMsg, new TbQueueCallback() { - @Override - public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entityView); - } - - @Override - public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entityView, t); - } - }); - } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}][{}] Failed to push entity view action to rule engine: {}", tenantId, entityViewId, DataConstants.ENTITY_CREATED, e); + String entityViewAsString = JacksonUtil.toString(entityView); + TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, entityView.getCustomerId()); + pushEntityCreatedEventToRuleEngine(tenantId, entityViewId, entityView.getCustomerId(), entityViewAsString, msgMetaData); + } catch (Exception e) { + log.warn("[{}][{}] Failed to push entity view action to rule engine: {}", tenantId, entityViewId, TbMsgType.ENTITY_CREATED.name(), e); } } From ddb03e4a1fe3ae687b4b8bfeebd7b8598df311f9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 4 Sep 2023 11:28:32 +0300 Subject: [PATCH 42/51] Make pushEntityEventToRuleEngine method generic to handle other actions --- .../service/edge/rpc/processor/BaseEdgeProcessor.java | 10 +++++----- .../edge/rpc/processor/asset/AssetEdgeProcessor.java | 2 +- .../rpc/processor/asset/AssetProfileEdgeProcessor.java | 2 +- .../processor/dashboard/DashboardEdgeProcessor.java | 2 +- .../edge/rpc/processor/device/DeviceEdgeProcessor.java | 2 +- .../processor/device/DeviceProfileEdgeProcessor.java | 2 +- .../processor/entityview/EntityViewEdgeProcessor.java | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index 1715c5212e..54aa99a5fd 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -581,18 +581,18 @@ public abstract class BaseEdgeProcessor { return metaData; } - protected void pushEntityCreatedEventToRuleEngine(TenantId tenantId, EntityId entityId, CustomerId customerId, - String entity, TbMsgMetaData metaData) { - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, entityId, customerId, metaData, TbMsgDataType.JSON, entity); + protected void pushEntityEventToRuleEngine(TenantId tenantId, EntityId entityId, CustomerId customerId, + TbMsgType msgType, String msgData, TbMsgMetaData metaData) { + TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, msgData); tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { - log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entity); + log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, msgData); } @Override public void onFailure(Throwable t) { - log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, entity, t); + log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, msgData, t); } }); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java index 71a39b16f4..aa0679a632 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java @@ -100,7 +100,7 @@ public class AssetEdgeProcessor extends BaseAssetProcessor { Asset asset = assetService.findAssetById(tenantId, assetId); String assetAsString = JacksonUtil.toString(asset); TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, asset.getCustomerId()); - pushEntityCreatedEventToRuleEngine(tenantId, assetId, asset.getCustomerId(), assetAsString, msgMetaData); + pushEntityEventToRuleEngine(tenantId, assetId, asset.getCustomerId(), TbMsgType.ENTITY_CREATED, assetAsString, msgMetaData); } catch (Exception e) { log.warn("[{}][{}] Failed to push asset action to rule engine: {}", tenantId, assetId, TbMsgType.ENTITY_CREATED.name(), e); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index 71c231fb6f..3fa69ed078 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -88,7 +88,7 @@ public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor { AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId); String assetProfileAsString = JacksonUtil.toString(assetProfile); TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null); - pushEntityCreatedEventToRuleEngine(tenantId, assetProfileId, null, assetProfileAsString, msgMetaData); + pushEntityEventToRuleEngine(tenantId, assetProfileId, null, TbMsgType.ENTITY_CREATED, assetProfileAsString, msgMetaData); } catch (Exception e) { log.warn("[{}][{}] Failed to push asset profile action to rule engine: {}", tenantId, assetProfileId, TbMsgType.ENTITY_CREATED.name(), e); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index 40cc6169b5..fc19d81789 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -92,7 +92,7 @@ public class DashboardEdgeProcessor extends BaseDashboardProcessor { Dashboard dashboard = dashboardService.findDashboardById(tenantId, dashboardId); String dashboardAsString = JacksonUtil.toString(dashboard); TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null); - pushEntityCreatedEventToRuleEngine(tenantId, dashboardId, null, dashboardAsString, msgMetaData); + pushEntityEventToRuleEngine(tenantId, dashboardId, null, TbMsgType.ENTITY_CREATED, dashboardAsString, msgMetaData); } catch (Exception e) { log.warn("[{}][{}] Failed to push dashboard action to rule engine: {}", tenantId, dashboardId, TbMsgType.ENTITY_CREATED.name(), e); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index cbc8c57e51..15edd4215d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -115,7 +115,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { Device device = deviceService.findDeviceById(tenantId, deviceId); String deviceAsString = JacksonUtil.toString(device); TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, device.getCustomerId()); - pushEntityCreatedEventToRuleEngine(tenantId, deviceId, device.getCustomerId(), deviceAsString, msgMetaData); + pushEntityEventToRuleEngine(tenantId, deviceId, device.getCustomerId(), TbMsgType.ENTITY_CREATED, deviceAsString, msgMetaData); } catch (Exception e) { log.warn("[{}][{}] Failed to push device action to rule engine: {}", tenantId, deviceId, TbMsgType.ENTITY_CREATED.name(), e); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index 6feeee625d..8f1e711775 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -88,7 +88,7 @@ public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor { DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); String deviceProfileAsString = JacksonUtil.toString(deviceProfile); TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null); - pushEntityCreatedEventToRuleEngine(tenantId, deviceProfileId, null, deviceProfileAsString, msgMetaData); + pushEntityEventToRuleEngine(tenantId, deviceProfileId, null, TbMsgType.ENTITY_CREATED, deviceProfileAsString, msgMetaData); } catch (Exception e) { log.warn("[{}][{}] Failed to push device profile action to rule engine: {}", tenantId, deviceProfileId, TbMsgType.ENTITY_CREATED.name(), e); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java index 6e624bce5f..01dd414aee 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java @@ -98,7 +98,7 @@ public class EntityViewEdgeProcessor extends BaseEntityViewProcessor { EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId); String entityViewAsString = JacksonUtil.toString(entityView); TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, entityView.getCustomerId()); - pushEntityCreatedEventToRuleEngine(tenantId, entityViewId, entityView.getCustomerId(), entityViewAsString, msgMetaData); + pushEntityEventToRuleEngine(tenantId, entityViewId, entityView.getCustomerId(), TbMsgType.ENTITY_CREATED, entityViewAsString, msgMetaData); } catch (Exception e) { log.warn("[{}][{}] Failed to push entity view action to rule engine: {}", tenantId, entityViewId, TbMsgType.ENTITY_CREATED.name(), e); } From f31da3c605b9d1634a0913ca98c15c1da36d15ac Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 4 Sep 2023 13:29:42 +0300 Subject: [PATCH 43/51] EdgeGrpcSession - Set tenant id on connect --- .../org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 37b71ce494..fd341365cd 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -762,6 +762,7 @@ public final class EdgeGrpcSession implements Closeable { Optional optional = ctx.getEdgeService().findEdgeByRoutingKey(TenantId.SYS_TENANT_ID, request.getEdgeRoutingKey()); if (optional.isPresent()) { edge = optional.get(); + this.tenantId = edge.getTenantId(); try { if (edge.getSecret().equals(request.getEdgeSecret())) { sessionOpenListener.accept(edge.getId(), this); From 550b67b45151e479281dae1e6de2d3e0cab91a22 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 4 Sep 2023 17:10:42 +0300 Subject: [PATCH 44/51] renamed proto directory to efento-proto --- .../coap/src/main/{proto => efento-proto}/proto_config.proto | 0 .../coap/src/main/{proto => efento-proto}/proto_device_info.proto | 0 .../main/{proto => efento-proto}/proto_measurement_types.proto | 0 .../src/main/{proto => efento-proto}/proto_measurements.proto | 0 .../coap/src/main/{proto => efento-proto}/proto_rule.proto | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename common/transport/coap/src/main/{proto => efento-proto}/proto_config.proto (100%) rename common/transport/coap/src/main/{proto => efento-proto}/proto_device_info.proto (100%) rename common/transport/coap/src/main/{proto => efento-proto}/proto_measurement_types.proto (100%) rename common/transport/coap/src/main/{proto => efento-proto}/proto_measurements.proto (100%) rename common/transport/coap/src/main/{proto => efento-proto}/proto_rule.proto (100%) diff --git a/common/transport/coap/src/main/proto/proto_config.proto b/common/transport/coap/src/main/efento-proto/proto_config.proto similarity index 100% rename from common/transport/coap/src/main/proto/proto_config.proto rename to common/transport/coap/src/main/efento-proto/proto_config.proto diff --git a/common/transport/coap/src/main/proto/proto_device_info.proto b/common/transport/coap/src/main/efento-proto/proto_device_info.proto similarity index 100% rename from common/transport/coap/src/main/proto/proto_device_info.proto rename to common/transport/coap/src/main/efento-proto/proto_device_info.proto diff --git a/common/transport/coap/src/main/proto/proto_measurement_types.proto b/common/transport/coap/src/main/efento-proto/proto_measurement_types.proto similarity index 100% rename from common/transport/coap/src/main/proto/proto_measurement_types.proto rename to common/transport/coap/src/main/efento-proto/proto_measurement_types.proto diff --git a/common/transport/coap/src/main/proto/proto_measurements.proto b/common/transport/coap/src/main/efento-proto/proto_measurements.proto similarity index 100% rename from common/transport/coap/src/main/proto/proto_measurements.proto rename to common/transport/coap/src/main/efento-proto/proto_measurements.proto diff --git a/common/transport/coap/src/main/proto/proto_rule.proto b/common/transport/coap/src/main/efento-proto/proto_rule.proto similarity index 100% rename from common/transport/coap/src/main/proto/proto_rule.proto rename to common/transport/coap/src/main/efento-proto/proto_rule.proto From 95b1f5fc95a7e7ac3b7923eb2fe8c6b932999649 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 4 Sep 2023 19:38:32 +0300 Subject: [PATCH 45/51] moved efento protos to proto/efento --- .../src/main/{efento-proto => proto/efento}/proto_config.proto | 0 .../main/{efento-proto => proto/efento}/proto_device_info.proto | 0 .../{efento-proto => proto/efento}/proto_measurement_types.proto | 0 .../main/{efento-proto => proto/efento}/proto_measurements.proto | 0 .../coap/src/main/{efento-proto => proto/efento}/proto_rule.proto | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename common/transport/coap/src/main/{efento-proto => proto/efento}/proto_config.proto (100%) rename common/transport/coap/src/main/{efento-proto => proto/efento}/proto_device_info.proto (100%) rename common/transport/coap/src/main/{efento-proto => proto/efento}/proto_measurement_types.proto (100%) rename common/transport/coap/src/main/{efento-proto => proto/efento}/proto_measurements.proto (100%) rename common/transport/coap/src/main/{efento-proto => proto/efento}/proto_rule.proto (100%) diff --git a/common/transport/coap/src/main/efento-proto/proto_config.proto b/common/transport/coap/src/main/proto/efento/proto_config.proto similarity index 100% rename from common/transport/coap/src/main/efento-proto/proto_config.proto rename to common/transport/coap/src/main/proto/efento/proto_config.proto diff --git a/common/transport/coap/src/main/efento-proto/proto_device_info.proto b/common/transport/coap/src/main/proto/efento/proto_device_info.proto similarity index 100% rename from common/transport/coap/src/main/efento-proto/proto_device_info.proto rename to common/transport/coap/src/main/proto/efento/proto_device_info.proto diff --git a/common/transport/coap/src/main/efento-proto/proto_measurement_types.proto b/common/transport/coap/src/main/proto/efento/proto_measurement_types.proto similarity index 100% rename from common/transport/coap/src/main/efento-proto/proto_measurement_types.proto rename to common/transport/coap/src/main/proto/efento/proto_measurement_types.proto diff --git a/common/transport/coap/src/main/efento-proto/proto_measurements.proto b/common/transport/coap/src/main/proto/efento/proto_measurements.proto similarity index 100% rename from common/transport/coap/src/main/efento-proto/proto_measurements.proto rename to common/transport/coap/src/main/proto/efento/proto_measurements.proto diff --git a/common/transport/coap/src/main/efento-proto/proto_rule.proto b/common/transport/coap/src/main/proto/efento/proto_rule.proto similarity index 100% rename from common/transport/coap/src/main/efento-proto/proto_rule.proto rename to common/transport/coap/src/main/proto/efento/proto_rule.proto From e1a79cc5940d2acb300a1c5ee433c1a7ca01121a Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 5 Sep 2023 11:00:59 +0300 Subject: [PATCH 46/51] compilation error fix --- .../transport/coap/src/main/proto/efento/proto_config.proto | 4 ++-- .../coap/src/main/proto/efento/proto_measurements.proto | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/transport/coap/src/main/proto/efento/proto_config.proto b/common/transport/coap/src/main/proto/efento/proto_config.proto index 5e0537a5d9..0903494245 100644 --- a/common/transport/coap/src/main/proto/efento/proto_config.proto +++ b/common/transport/coap/src/main/proto/efento/proto_config.proto @@ -15,8 +15,8 @@ */ syntax = "proto3"; -import "proto_measurement_types.proto"; -import "proto_rule.proto"; +import "efento/proto_measurement_types.proto"; +import "efento/proto_rule.proto"; option java_package = "org.thingsboard.server.gen.transport.coap"; option java_outer_classname = "ConfigProtos"; diff --git a/common/transport/coap/src/main/proto/efento/proto_measurements.proto b/common/transport/coap/src/main/proto/efento/proto_measurements.proto index 27bd6e3313..fd93b38b82 100644 --- a/common/transport/coap/src/main/proto/efento/proto_measurements.proto +++ b/common/transport/coap/src/main/proto/efento/proto_measurements.proto @@ -14,7 +14,7 @@ * limitations under the License. */ syntax = "proto3"; -import "proto_measurement_types.proto"; +import "efento/proto_measurement_types.proto"; option java_package = "org.thingsboard.server.gen.transport.coap"; option java_outer_classname = "MeasurementsProtos"; From 3c51a25eac4a1e28f4b57e9a8d417620118086a8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 5 Sep 2023 11:47:05 +0300 Subject: [PATCH 47/51] UI: Fix dashboard component styles. --- .../home/components/dashboard/dashboard.component.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html index eaf238d26e..d8b511f076 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html @@ -16,14 +16,14 @@ -->
-
+
- + Date: Tue, 5 Sep 2023 12:18:59 +0300 Subject: [PATCH 48/51] UI: Improve widget models --- .../core/services/dashboard-utils.service.ts | 20 ++++++++++++++++++- .../dashboard-pages.routing.module.ts | 3 --- .../attribute/attribute-table.component.ts | 1 - .../dashboard-page.component.ts | 3 --- ui-ngx/src/app/shared/models/widget.models.ts | 13 +++++++----- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 3bca1bc96a..bb4c738516 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -223,6 +223,15 @@ export class DashboardUtilsService { public validateAndUpdateWidget(widget: Widget): Widget { widget.config = this.validateAndUpdateWidgetConfig(widget.config, widget.type); widget = this.validateAndUpdateWidgetTypeFqn(widget); + if (isDefined((widget as any).title)) { + delete (widget as any).title; + } + if (isDefined((widget as any).image)) { + delete (widget as any).image; + } + if (isDefined((widget as any).description)) { + delete (widget as any).description; + } // Temp workaround if (['system.charts.state_chart', 'system.charts.basic_timeseries', @@ -246,12 +255,21 @@ export class DashboardUtilsService { } private validateAndUpdateWidgetTypeFqn(widget: Widget): Widget { + const w = widget as any; if (!isValidWidgetFullFqn(widget.typeFullFqn)) { - const w = widget as any; if (isDefinedAndNotNull(w.isSystemType) && isNotEmptyStr(w.bundleAlias) && isNotEmptyStr(w.typeAlias)) { widget.typeFullFqn = (w.isSystemType ? 'system' : 'tenant') + '.' + w.bundleAlias + '.' + w.typeAlias; } } + if (isDefined(w.isSystemType)) { + delete w.isSystemType; + } + if (isDefined(w.bundleAlias)) { + delete w.bundleAlias; + } + if (isDefined(w.typeAlias)) { + delete w.typeAlias; + } // Temp workaround if (widget.typeFullFqn === 'system.charts.timeseries') { widget.typeFullFqn = 'system.charts.basic_timeseries'; diff --git a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts index 4963818aa0..a89f467e1e 100644 --- a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts +++ b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts @@ -40,9 +40,6 @@ export class WidgetEditorDashboardResolver implements Resolve { const widget: Widget = { typeFullFqn: 'system.customWidget', type: editWidgetInfo.type, - title: 'My widget', - image: null, - description: null, sizeX: editWidgetInfo.sizeX * 2, sizeY: editWidgetInfo.sizeY * 2, row: 2, diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index 0837474a87..872e124f3a 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -585,7 +585,6 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI const widget: Widget = { typeFullFqn: widgetInfo.fullFqn, type: widgetInfo.type, - title: widgetInfo.widgetName, sizeX, sizeY, row: 0, diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index e24f1cad07..7b84dbd6d0 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -1162,9 +1162,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC let newWidget: Widget = { typeFullFqn: widgetTypeInfo.fullFqn, type: widgetTypeInfo.type, - title: 'New widget', - image: null, - description: null, sizeX: widgetTypeInfo.sizeX, sizeY: widgetTypeInfo.sizeY, config, diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 21de5376ab..c04eb6f7ec 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -681,7 +681,13 @@ export interface WidgetConfig { [key: string]: any; } -export interface Widget extends WidgetInfo{ +export interface BaseWidgetInfo { + id?: string; + typeFullFqn: string; + type: widgetType; +} + +export interface Widget extends BaseWidgetInfo { typeId?: WidgetTypeId; sizeX: number; sizeY: number; @@ -690,10 +696,7 @@ export interface Widget extends WidgetInfo{ config: WidgetConfig; } -export interface WidgetInfo { - id?: string; - typeFullFqn: string; - type: widgetType; +export interface WidgetInfo extends BaseWidgetInfo { title: string; image?: string; description?: string; From 08f26bad5b502d406ff5d343093c832183ba3dd6 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 5 Sep 2023 12:43:38 +0300 Subject: [PATCH 49/51] fixed addSystemAlarmComment method --- .../entitiy/alarm/DefaultTbAlarmService.java | 2 +- .../alarm/DefaultTbAlarmServiceTest.java | 66 +++++++++++++++++++ .../common/data/alarm/AlarmComment.java | 2 + 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 91223ef69d..bd09b04a02 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -237,7 +237,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb AlarmComment alarmComment = AlarmComment.builder() .alarmId(alarm.getId()) .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode()) + .comment(commentNode) .build(); try { alarmCommentService.saveAlarmComment(alarm, alarmComment, user); diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java index 0318360a91..b3e8941364 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.entitiy.alarm; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,14 +24,20 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.edge.EdgeService; @@ -39,6 +46,8 @@ import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; +import java.util.Collections; +import java.util.List; import java.util.UUID; import static org.mockito.ArgumentMatchers.any; @@ -123,4 +132,61 @@ public class DefaultTbAlarmServiceTest { verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.DELETED), any()); verify(alarmSubscriptionService, times(1)).deleteAlarm(any(), any()); } + + @Test + public void testUnassignAlarm() throws ThingsboardException { + AlarmInfo alarm = new AlarmInfo(); + alarm.setId(new AlarmId(UUID.randomUUID())); + when(alarmSubscriptionService.unassignAlarm(any(), any(), anyLong())) + .thenReturn(AlarmApiCallResult.builder().successful(true).modified(true).alarm(alarm).build()); + + User user = new User(); + user.setEmail("testEmail@gmail.com"); + user.setId(new UserId(UUID.randomUUID())); + service.unassign(new Alarm(), 0L, user); + + ObjectNode commentNode = JacksonUtil.newObjectNode(); + commentNode.put("subtype", "ASSIGN"); + commentNode.put("text", "Alarm was unassigned by user " + user.getTitle()); + commentNode.put("userId", user.getId().getId().toString()); + AlarmComment expectedAlarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(commentNode) + .build(); + + verify(alarmCommentService, times(1)) + .saveAlarmComment(eq(alarm), eq(expectedAlarmComment), eq(user)); + } + + @Test + public void testUnassignDeletedUserAlarms() throws ThingsboardException { + AlarmInfo alarm = new AlarmInfo(); + alarm.setId(new AlarmId(UUID.randomUUID())); + + when(alarmService.findAlarmIdsByAssigneeId(any(), any(), any())) + .thenReturn(new PageData<>(List.of(alarm.getId()), 0, 1, false)) + .thenReturn(new PageData<>(Collections.EMPTY_LIST, 0, 0, false)); + when(alarmSubscriptionService.unassignAlarm(any(), any(), anyLong())) + .thenReturn(AlarmApiCallResult.builder().successful(true).modified(true).alarm(alarm).build()); + + User user = new User(); + user.setEmail("testEmail@gmail.com"); + user.setId(new UserId(UUID.randomUUID())); + service.unassignDeletedUserAlarms(new TenantId(UUID.randomUUID()), user, System.currentTimeMillis()); + + ObjectNode commentNode = JacksonUtil.newObjectNode(); + commentNode.put("subtype", "ASSIGN"); + commentNode.put("text", String.format("Alarm was unassigned because user %s - was deleted", user.getTitle())); + AlarmComment expectedAlarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(commentNode) + .build(); + + verify(alarmCommentService, times(1)) + .saveAlarmComment(eq(alarm), eq(expectedAlarmComment), eq(null)); + } + + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java index 982e0f94d1..76ea06d27a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -22,6 +22,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.id.AlarmCommentId; @@ -44,6 +45,7 @@ public class AlarmComment extends BaseData implements HasName { @ApiModelProperty(position = 6, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode") @NoXss @Length(fieldName = "comment", max = 10000) + @EqualsAndHashCode.Include private transient JsonNode comment; @ApiModelProperty(position = 1, value = "JSON object with the alarm comment Id. " + From 982f25f4811227c9e163b765bde507a424cd0adb Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 5 Sep 2023 15:39:56 +0300 Subject: [PATCH 50/51] UI: Fix save widget type method. --- ui-ngx/src/app/core/http/widget.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts index 86a3a2d48d..6affb01efe 100644 --- a/ui-ngx/src/app/core/http/widget.service.ts +++ b/ui-ngx/src/app/core/http/widget.service.ts @@ -207,7 +207,7 @@ export class WidgetService { public saveWidgetType(widgetTypeDetails: WidgetTypeDetails, config?: RequestConfig): Observable { - return this.http.post(`/api/widgetType`, + return this.http.post(`/api/widgetType`, widgetTypeDetails, defaultHttpOptionsFromConfig(config)); } From 6703ec0370363584e1e0f5441fdbfe058050fcef Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 5 Sep 2023 16:04:54 +0300 Subject: [PATCH 51/51] State service tests improved --- .../server/service/state/DefaultDeviceStateServiceTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index e37e19b382..ccb0b5e26c 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -295,6 +295,7 @@ public class DefaultDeviceStateServiceTest { Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); long newTimeout = 1; + Thread.sleep(newTimeout); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); activityVerify(false); @@ -330,6 +331,7 @@ public class DefaultDeviceStateServiceTest { Mockito.reset(telemetrySubscriptionService); long newTimeout = 1; + Thread.sleep(newTimeout); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any());