Showing
16 changed files
with
341 additions
and
238 deletions
@@ -110,8 +110,11 @@ public class AlarmController extends BaseController { | @@ -110,8 +110,11 @@ public class AlarmController extends BaseController { | ||
110 | checkParameter(ALARM_ID, strAlarmId); | 110 | checkParameter(ALARM_ID, strAlarmId); |
111 | try { | 111 | try { |
112 | AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); | 112 | AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); |
113 | - checkAlarmId(alarmId, Operation.WRITE); | 113 | + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); |
114 | 114 | ||
115 | + logEntityAction(alarm.getOriginator(), alarm, | ||
116 | + getCurrentUser().getCustomerId(), | ||
117 | + ActionType.ALARM_DELETE, null); | ||
115 | sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.DELETED); | 118 | sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.DELETED); |
116 | 119 | ||
117 | return alarmService.deleteAlarm(getTenantId(), alarmId); | 120 | return alarmService.deleteAlarm(getTenantId(), alarmId); |
@@ -17,7 +17,6 @@ package org.thingsboard.server.controller; | @@ -17,7 +17,6 @@ package org.thingsboard.server.controller; | ||
17 | 17 | ||
18 | import com.fasterxml.jackson.core.JsonProcessingException; | 18 | import com.fasterxml.jackson.core.JsonProcessingException; |
19 | import com.fasterxml.jackson.databind.ObjectMapper; | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | -import com.fasterxml.jackson.databind.node.ArrayNode; | ||
21 | import com.fasterxml.jackson.databind.node.ObjectNode; | 20 | import com.fasterxml.jackson.databind.node.ObjectNode; |
22 | import lombok.Getter; | 21 | import lombok.Getter; |
23 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
@@ -31,7 +30,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler; | @@ -31,7 +30,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler; | ||
31 | import org.thingsboard.server.common.data.Customer; | 30 | import org.thingsboard.server.common.data.Customer; |
32 | import org.thingsboard.server.common.data.Dashboard; | 31 | import org.thingsboard.server.common.data.Dashboard; |
33 | import org.thingsboard.server.common.data.DashboardInfo; | 32 | import org.thingsboard.server.common.data.DashboardInfo; |
34 | -import org.thingsboard.server.common.data.DataConstants; | ||
35 | import org.thingsboard.server.common.data.Device; | 33 | import org.thingsboard.server.common.data.Device; |
36 | import org.thingsboard.server.common.data.DeviceInfo; | 34 | import org.thingsboard.server.common.data.DeviceInfo; |
37 | import org.thingsboard.server.common.data.DeviceProfile; | 35 | import org.thingsboard.server.common.data.DeviceProfile; |
@@ -79,10 +77,6 @@ import org.thingsboard.server.common.data.id.TenantProfileId; | @@ -79,10 +77,6 @@ import org.thingsboard.server.common.data.id.TenantProfileId; | ||
79 | import org.thingsboard.server.common.data.id.UserId; | 77 | import org.thingsboard.server.common.data.id.UserId; |
80 | import org.thingsboard.server.common.data.id.WidgetTypeId; | 78 | import org.thingsboard.server.common.data.id.WidgetTypeId; |
81 | import org.thingsboard.server.common.data.id.WidgetsBundleId; | 79 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
82 | -import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
83 | -import org.thingsboard.server.common.data.kv.DataType; | ||
84 | -import org.thingsboard.server.common.data.kv.KvEntry; | ||
85 | -import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
86 | import org.thingsboard.server.common.data.page.PageLink; | 80 | import org.thingsboard.server.common.data.page.PageLink; |
87 | import org.thingsboard.server.common.data.page.SortOrder; | 81 | import org.thingsboard.server.common.data.page.SortOrder; |
88 | import org.thingsboard.server.common.data.page.TimePageLink; | 82 | import org.thingsboard.server.common.data.page.TimePageLink; |
@@ -94,9 +88,6 @@ import org.thingsboard.server.common.data.rule.RuleChainType; | @@ -94,9 +88,6 @@ import org.thingsboard.server.common.data.rule.RuleChainType; | ||
94 | import org.thingsboard.server.common.data.rule.RuleNode; | 88 | import org.thingsboard.server.common.data.rule.RuleNode; |
95 | import org.thingsboard.server.common.data.widget.WidgetTypeDetails; | 89 | import org.thingsboard.server.common.data.widget.WidgetTypeDetails; |
96 | import org.thingsboard.server.common.data.widget.WidgetsBundle; | 90 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
97 | -import org.thingsboard.server.common.msg.TbMsg; | ||
98 | -import org.thingsboard.server.common.msg.TbMsgDataType; | ||
99 | -import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
100 | import org.thingsboard.server.dao.asset.AssetService; | 91 | import org.thingsboard.server.dao.asset.AssetService; |
101 | import org.thingsboard.server.dao.attributes.AttributesService; | 92 | import org.thingsboard.server.dao.attributes.AttributesService; |
102 | import org.thingsboard.server.dao.audit.AuditLogService; | 93 | import org.thingsboard.server.dao.audit.AuditLogService; |
@@ -127,6 +118,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; | @@ -127,6 +118,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; | ||
127 | import org.thingsboard.server.queue.discovery.PartitionService; | 118 | import org.thingsboard.server.queue.discovery.PartitionService; |
128 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; | 119 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
129 | import org.thingsboard.server.queue.util.TbCoreComponent; | 120 | import org.thingsboard.server.queue.util.TbCoreComponent; |
121 | +import org.thingsboard.server.service.action.RuleEngineEntityActionService; | ||
130 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 122 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
131 | import org.thingsboard.server.service.firmware.FirmwareStateService; | 123 | import org.thingsboard.server.service.firmware.FirmwareStateService; |
132 | import org.thingsboard.server.service.edge.EdgeNotificationService; | 124 | import org.thingsboard.server.service.edge.EdgeNotificationService; |
@@ -147,11 +139,9 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | @@ -147,11 +139,9 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | ||
147 | import javax.mail.MessagingException; | 139 | import javax.mail.MessagingException; |
148 | import javax.servlet.http.HttpServletResponse; | 140 | import javax.servlet.http.HttpServletResponse; |
149 | import java.util.List; | 141 | import java.util.List; |
150 | -import java.util.Map; | ||
151 | import java.util.Optional; | 142 | import java.util.Optional; |
152 | import java.util.Set; | 143 | import java.util.Set; |
153 | import java.util.UUID; | 144 | import java.util.UUID; |
154 | -import java.util.stream.Collectors; | ||
155 | 145 | ||
156 | import static org.thingsboard.server.dao.service.Validator.validateId; | 146 | import static org.thingsboard.server.dao.service.Validator.validateId; |
157 | 147 | ||
@@ -281,6 +271,9 @@ public abstract class BaseController { | @@ -281,6 +271,9 @@ public abstract class BaseController { | ||
281 | @Autowired(required = false) | 271 | @Autowired(required = false) |
282 | protected EdgeGrpcService edgeGrpcService; | 272 | protected EdgeGrpcService edgeGrpcService; |
283 | 273 | ||
274 | + @Autowired | ||
275 | + protected RuleEngineEntityActionService ruleEngineEntityActionService; | ||
276 | + | ||
284 | @Value("${server.log_controller_error_stack_trace}") | 277 | @Value("${server.log_controller_error_stack_trace}") |
285 | @Getter | 278 | @Getter |
286 | private boolean logControllerErrorStackTrace; | 279 | private boolean logControllerErrorStackTrace; |
@@ -811,7 +804,7 @@ public abstract class BaseController { | @@ -811,7 +804,7 @@ public abstract class BaseController { | ||
811 | customerId = user.getCustomerId(); | 804 | customerId = user.getCustomerId(); |
812 | } | 805 | } |
813 | if (e == null) { | 806 | if (e == null) { |
814 | - pushEntityActionToRuleEngine(entityId, entity, user, customerId, actionType, additionalInfo); | 807 | + ruleEngineEntityActionService.pushEntityActionToRuleEngine(entityId, entity, user.getTenantId(), customerId, actionType, user, additionalInfo); |
815 | } | 808 | } |
816 | auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); | 809 | auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); |
817 | } | 810 | } |
@@ -821,184 +814,6 @@ public abstract class BaseController { | @@ -821,184 +814,6 @@ public abstract class BaseController { | ||
821 | return error != null ? (Exception.class.isInstance(error) ? (Exception) error : new Exception(error)) : null; | 814 | return error != null ? (Exception.class.isInstance(error) ? (Exception) error : new Exception(error)) : null; |
822 | } | 815 | } |
823 | 816 | ||
824 | - private <E extends HasName, I extends EntityId> void pushEntityActionToRuleEngine(I entityId, E entity, User user, CustomerId customerId, | ||
825 | - ActionType actionType, Object... additionalInfo) { | ||
826 | - String msgType = null; | ||
827 | - switch (actionType) { | ||
828 | - case ADDED: | ||
829 | - msgType = DataConstants.ENTITY_CREATED; | ||
830 | - break; | ||
831 | - case DELETED: | ||
832 | - msgType = DataConstants.ENTITY_DELETED; | ||
833 | - break; | ||
834 | - case UPDATED: | ||
835 | - msgType = DataConstants.ENTITY_UPDATED; | ||
836 | - break; | ||
837 | - case ASSIGNED_TO_CUSTOMER: | ||
838 | - msgType = DataConstants.ENTITY_ASSIGNED; | ||
839 | - break; | ||
840 | - case UNASSIGNED_FROM_CUSTOMER: | ||
841 | - msgType = DataConstants.ENTITY_UNASSIGNED; | ||
842 | - break; | ||
843 | - case ATTRIBUTES_UPDATED: | ||
844 | - msgType = DataConstants.ATTRIBUTES_UPDATED; | ||
845 | - break; | ||
846 | - case ATTRIBUTES_DELETED: | ||
847 | - msgType = DataConstants.ATTRIBUTES_DELETED; | ||
848 | - break; | ||
849 | - case ALARM_ACK: | ||
850 | - msgType = DataConstants.ALARM_ACK; | ||
851 | - break; | ||
852 | - case ALARM_CLEAR: | ||
853 | - msgType = DataConstants.ALARM_CLEAR; | ||
854 | - break; | ||
855 | - case ASSIGNED_FROM_TENANT: | ||
856 | - msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT; | ||
857 | - break; | ||
858 | - case ASSIGNED_TO_TENANT: | ||
859 | - msgType = DataConstants.ENTITY_ASSIGNED_TO_TENANT; | ||
860 | - break; | ||
861 | - case PROVISION_SUCCESS: | ||
862 | - msgType = DataConstants.PROVISION_SUCCESS; | ||
863 | - break; | ||
864 | - case PROVISION_FAILURE: | ||
865 | - msgType = DataConstants.PROVISION_FAILURE; | ||
866 | - break; | ||
867 | - case TIMESERIES_UPDATED: | ||
868 | - msgType = DataConstants.TIMESERIES_UPDATED; | ||
869 | - break; | ||
870 | - case TIMESERIES_DELETED: | ||
871 | - msgType = DataConstants.TIMESERIES_DELETED; | ||
872 | - break; | ||
873 | - case ASSIGNED_TO_EDGE: | ||
874 | - msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE; | ||
875 | - break; | ||
876 | - case UNASSIGNED_FROM_EDGE: | ||
877 | - msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE; | ||
878 | - break; | ||
879 | - } | ||
880 | - if (!StringUtils.isEmpty(msgType)) { | ||
881 | - try { | ||
882 | - TbMsgMetaData metaData = new TbMsgMetaData(); | ||
883 | - metaData.putValue("userId", user.getId().toString()); | ||
884 | - metaData.putValue("userName", user.getName()); | ||
885 | - if (customerId != null && !customerId.isNullUid()) { | ||
886 | - metaData.putValue("customerId", customerId.toString()); | ||
887 | - } | ||
888 | - if (actionType == ActionType.ASSIGNED_TO_CUSTOMER) { | ||
889 | - String strCustomerId = extractParameter(String.class, 1, additionalInfo); | ||
890 | - String strCustomerName = extractParameter(String.class, 2, additionalInfo); | ||
891 | - metaData.putValue("assignedCustomerId", strCustomerId); | ||
892 | - metaData.putValue("assignedCustomerName", strCustomerName); | ||
893 | - } else if (actionType == ActionType.UNASSIGNED_FROM_CUSTOMER) { | ||
894 | - String strCustomerId = extractParameter(String.class, 1, additionalInfo); | ||
895 | - String strCustomerName = extractParameter(String.class, 2, additionalInfo); | ||
896 | - metaData.putValue("unassignedCustomerId", strCustomerId); | ||
897 | - metaData.putValue("unassignedCustomerName", strCustomerName); | ||
898 | - } else if (actionType == ActionType.ASSIGNED_FROM_TENANT) { | ||
899 | - String strTenantId = extractParameter(String.class, 0, additionalInfo); | ||
900 | - String strTenantName = extractParameter(String.class, 1, additionalInfo); | ||
901 | - metaData.putValue("assignedFromTenantId", strTenantId); | ||
902 | - metaData.putValue("assignedFromTenantName", strTenantName); | ||
903 | - } else if (actionType == ActionType.ASSIGNED_TO_TENANT) { | ||
904 | - String strTenantId = extractParameter(String.class, 0, additionalInfo); | ||
905 | - String strTenantName = extractParameter(String.class, 1, additionalInfo); | ||
906 | - metaData.putValue("assignedToTenantId", strTenantId); | ||
907 | - metaData.putValue("assignedToTenantName", strTenantName); | ||
908 | - } else if (actionType == ActionType.ASSIGNED_TO_EDGE) { | ||
909 | - String strEdgeId = extractParameter(String.class, 1, additionalInfo); | ||
910 | - String strEdgeName = extractParameter(String.class, 2, additionalInfo); | ||
911 | - metaData.putValue("assignedEdgeId", strEdgeId); | ||
912 | - metaData.putValue("assignedEdgeName", strEdgeName); | ||
913 | - } else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { | ||
914 | - String strEdgeId = extractParameter(String.class, 1, additionalInfo); | ||
915 | - String strEdgeName = extractParameter(String.class, 2, additionalInfo); | ||
916 | - metaData.putValue("unassignedEdgeId", strEdgeId); | ||
917 | - metaData.putValue("unassignedEdgeName", strEdgeName); | ||
918 | - } | ||
919 | - ObjectNode entityNode; | ||
920 | - if (entity != null) { | ||
921 | - entityNode = json.valueToTree(entity); | ||
922 | - if (entityId.getEntityType() == EntityType.DASHBOARD) { | ||
923 | - entityNode.put("configuration", ""); | ||
924 | - } | ||
925 | - } else { | ||
926 | - entityNode = json.createObjectNode(); | ||
927 | - if (actionType == ActionType.ATTRIBUTES_UPDATED) { | ||
928 | - String scope = extractParameter(String.class, 0, additionalInfo); | ||
929 | - @SuppressWarnings("unchecked") | ||
930 | - List<AttributeKvEntry> attributes = extractParameter(List.class, 1, additionalInfo); | ||
931 | - metaData.putValue(DataConstants.SCOPE, scope); | ||
932 | - if (attributes != null) { | ||
933 | - for (AttributeKvEntry attr : attributes) { | ||
934 | - addKvEntry(entityNode, attr); | ||
935 | - } | ||
936 | - } | ||
937 | - } else if (actionType == ActionType.ATTRIBUTES_DELETED) { | ||
938 | - String scope = extractParameter(String.class, 0, additionalInfo); | ||
939 | - @SuppressWarnings("unchecked") | ||
940 | - List<String> keys = extractParameter(List.class, 1, additionalInfo); | ||
941 | - metaData.putValue(DataConstants.SCOPE, scope); | ||
942 | - ArrayNode attrsArrayNode = entityNode.putArray("attributes"); | ||
943 | - if (keys != null) { | ||
944 | - keys.forEach(attrsArrayNode::add); | ||
945 | - } | ||
946 | - } else if (actionType == ActionType.TIMESERIES_UPDATED) { | ||
947 | - @SuppressWarnings("unchecked") | ||
948 | - List<TsKvEntry> timeseries = extractParameter(List.class, 0, additionalInfo); | ||
949 | - addTimeseries(entityNode, timeseries); | ||
950 | - } else if (actionType == ActionType.TIMESERIES_DELETED) { | ||
951 | - @SuppressWarnings("unchecked") | ||
952 | - List<String> keys = extractParameter(List.class, 0, additionalInfo); | ||
953 | - if (keys != null) { | ||
954 | - ArrayNode timeseriesArrayNode = entityNode.putArray("timeseries"); | ||
955 | - keys.forEach(timeseriesArrayNode::add); | ||
956 | - } | ||
957 | - entityNode.put("startTs", extractParameter(Long.class, 1, additionalInfo)); | ||
958 | - entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo)); | ||
959 | - } | ||
960 | - } | ||
961 | - TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); | ||
962 | - TenantId tenantId = user.getTenantId(); | ||
963 | - if (tenantId.isNullUid()) { | ||
964 | - if (entity instanceof HasTenantId) { | ||
965 | - tenantId = ((HasTenantId) entity).getTenantId(); | ||
966 | - } | ||
967 | - } | ||
968 | - tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); | ||
969 | - } catch (Exception e) { | ||
970 | - log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); | ||
971 | - } | ||
972 | - } | ||
973 | - } | ||
974 | - | ||
975 | - private void addKvEntry(ObjectNode entityNode, KvEntry kvEntry) throws Exception { | ||
976 | - if (kvEntry.getDataType() == DataType.BOOLEAN) { | ||
977 | - kvEntry.getBooleanValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); | ||
978 | - } else if (kvEntry.getDataType() == DataType.DOUBLE) { | ||
979 | - kvEntry.getDoubleValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); | ||
980 | - } else if (kvEntry.getDataType() == DataType.LONG) { | ||
981 | - kvEntry.getLongValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); | ||
982 | - } else if (kvEntry.getDataType() == DataType.JSON) { | ||
983 | - if (kvEntry.getJsonValue().isPresent()) { | ||
984 | - entityNode.set(kvEntry.getKey(), json.readTree(kvEntry.getJsonValue().get())); | ||
985 | - } | ||
986 | - } else { | ||
987 | - entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString()); | ||
988 | - } | ||
989 | - } | ||
990 | - | ||
991 | - private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) { | ||
992 | - T result = null; | ||
993 | - if (additionalInfo != null && additionalInfo.length > index) { | ||
994 | - Object paramObject = additionalInfo[index]; | ||
995 | - if (clazz.isInstance(paramObject)) { | ||
996 | - result = clazz.cast(paramObject); | ||
997 | - } | ||
998 | - } | ||
999 | - return result; | ||
1000 | - } | ||
1001 | - | ||
1002 | protected <E extends HasName> String entityToStr(E entity) { | 817 | protected <E extends HasName> String entityToStr(E entity) { |
1003 | try { | 818 | try { |
1004 | return json.writeValueAsString(json.valueToTree(entity)); | 819 | return json.writeValueAsString(json.valueToTree(entity)); |
@@ -1095,23 +910,6 @@ public abstract class BaseController { | @@ -1095,23 +910,6 @@ public abstract class BaseController { | ||
1095 | return result; | 910 | return result; |
1096 | } | 911 | } |
1097 | 912 | ||
1098 | - private void addTimeseries(ObjectNode entityNode, List<TsKvEntry> timeseries) throws Exception { | ||
1099 | - if (timeseries != null && !timeseries.isEmpty()) { | ||
1100 | - ArrayNode result = entityNode.putArray("timeseries"); | ||
1101 | - Map<Long, List<TsKvEntry>> groupedTelemetry = timeseries.stream() | ||
1102 | - .collect(Collectors.groupingBy(TsKvEntry::getTs)); | ||
1103 | - for (Map.Entry<Long, List<TsKvEntry>> entry : groupedTelemetry.entrySet()) { | ||
1104 | - ObjectNode element = json.createObjectNode(); | ||
1105 | - element.put("ts", entry.getKey()); | ||
1106 | - ObjectNode values = element.putObject("values"); | ||
1107 | - for (TsKvEntry tsKvEntry : entry.getValue()) { | ||
1108 | - addKvEntry(values, tsKvEntry); | ||
1109 | - } | ||
1110 | - result.add(element); | ||
1111 | - } | ||
1112 | - } | ||
1113 | - } | ||
1114 | - | ||
1115 | protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException { | 913 | protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException { |
1116 | String dashboardId = additionalInfo.has(requiredFields) ? additionalInfo.get(requiredFields).asText() : null; | 914 | String dashboardId = additionalInfo.has(requiredFields) ? additionalInfo.get(requiredFields).asText() : null; |
1117 | if (dashboardId != null && !dashboardId.equals("null")) { | 915 | if (dashboardId != null && !dashboardId.equals("null")) { |
application/src/main/java/org/thingsboard/server/service/action/RuleEngineEntityActionService.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.service.action; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
19 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
20 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
21 | +import lombok.RequiredArgsConstructor; | ||
22 | +import lombok.extern.slf4j.Slf4j; | ||
23 | +import org.apache.commons.lang3.StringUtils; | ||
24 | +import org.springframework.stereotype.Service; | ||
25 | +import org.thingsboard.server.common.data.DataConstants; | ||
26 | +import org.thingsboard.server.common.data.EntityType; | ||
27 | +import org.thingsboard.server.common.data.HasName; | ||
28 | +import org.thingsboard.server.common.data.HasTenantId; | ||
29 | +import org.thingsboard.server.common.data.User; | ||
30 | +import org.thingsboard.server.common.data.audit.ActionType; | ||
31 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
32 | +import org.thingsboard.server.common.data.id.EntityId; | ||
33 | +import org.thingsboard.server.common.data.id.TenantId; | ||
34 | +import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
35 | +import org.thingsboard.server.common.data.kv.DataType; | ||
36 | +import org.thingsboard.server.common.data.kv.KvEntry; | ||
37 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
38 | +import org.thingsboard.server.common.msg.TbMsg; | ||
39 | +import org.thingsboard.server.common.msg.TbMsgDataType; | ||
40 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
41 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
42 | +import org.thingsboard.server.service.queue.TbClusterService; | ||
43 | + | ||
44 | +import java.util.List; | ||
45 | +import java.util.Map; | ||
46 | +import java.util.stream.Collectors; | ||
47 | + | ||
48 | +@TbCoreComponent | ||
49 | +@Service | ||
50 | +@RequiredArgsConstructor | ||
51 | +@Slf4j | ||
52 | +public class RuleEngineEntityActionService { | ||
53 | + private final TbClusterService tbClusterService; | ||
54 | + | ||
55 | + private static final ObjectMapper json = new ObjectMapper(); | ||
56 | + | ||
57 | + public void pushEntityActionToRuleEngine(EntityId entityId, HasName entity, TenantId tenantId, CustomerId customerId, | ||
58 | + ActionType actionType, User user, Object... additionalInfo) { | ||
59 | + String msgType = null; | ||
60 | + switch (actionType) { | ||
61 | + case ADDED: | ||
62 | + msgType = DataConstants.ENTITY_CREATED; | ||
63 | + break; | ||
64 | + case DELETED: | ||
65 | + msgType = DataConstants.ENTITY_DELETED; | ||
66 | + break; | ||
67 | + case UPDATED: | ||
68 | + msgType = DataConstants.ENTITY_UPDATED; | ||
69 | + break; | ||
70 | + case ASSIGNED_TO_CUSTOMER: | ||
71 | + msgType = DataConstants.ENTITY_ASSIGNED; | ||
72 | + break; | ||
73 | + case UNASSIGNED_FROM_CUSTOMER: | ||
74 | + msgType = DataConstants.ENTITY_UNASSIGNED; | ||
75 | + break; | ||
76 | + case ATTRIBUTES_UPDATED: | ||
77 | + msgType = DataConstants.ATTRIBUTES_UPDATED; | ||
78 | + break; | ||
79 | + case ATTRIBUTES_DELETED: | ||
80 | + msgType = DataConstants.ATTRIBUTES_DELETED; | ||
81 | + break; | ||
82 | + case ALARM_ACK: | ||
83 | + msgType = DataConstants.ALARM_ACK; | ||
84 | + break; | ||
85 | + case ALARM_CLEAR: | ||
86 | + msgType = DataConstants.ALARM_CLEAR; | ||
87 | + break; | ||
88 | + case ALARM_DELETE: | ||
89 | + msgType = DataConstants.ALARM_DELETE; | ||
90 | + break; | ||
91 | + case ASSIGNED_FROM_TENANT: | ||
92 | + msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT; | ||
93 | + break; | ||
94 | + case ASSIGNED_TO_TENANT: | ||
95 | + msgType = DataConstants.ENTITY_ASSIGNED_TO_TENANT; | ||
96 | + break; | ||
97 | + case PROVISION_SUCCESS: | ||
98 | + msgType = DataConstants.PROVISION_SUCCESS; | ||
99 | + break; | ||
100 | + case PROVISION_FAILURE: | ||
101 | + msgType = DataConstants.PROVISION_FAILURE; | ||
102 | + break; | ||
103 | + case TIMESERIES_UPDATED: | ||
104 | + msgType = DataConstants.TIMESERIES_UPDATED; | ||
105 | + break; | ||
106 | + case TIMESERIES_DELETED: | ||
107 | + msgType = DataConstants.TIMESERIES_DELETED; | ||
108 | + break; | ||
109 | + case ASSIGNED_TO_EDGE: | ||
110 | + msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE; | ||
111 | + break; | ||
112 | + case UNASSIGNED_FROM_EDGE: | ||
113 | + msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE; | ||
114 | + break; | ||
115 | + } | ||
116 | + if (!StringUtils.isEmpty(msgType)) { | ||
117 | + try { | ||
118 | + TbMsgMetaData metaData = new TbMsgMetaData(); | ||
119 | + if (user != null) { | ||
120 | + metaData.putValue("userId", user.getId().toString()); | ||
121 | + metaData.putValue("userName", user.getName()); | ||
122 | + } | ||
123 | + if (customerId != null && !customerId.isNullUid()) { | ||
124 | + metaData.putValue("customerId", customerId.toString()); | ||
125 | + } | ||
126 | + if (actionType == ActionType.ASSIGNED_TO_CUSTOMER) { | ||
127 | + String strCustomerId = extractParameter(String.class, 1, additionalInfo); | ||
128 | + String strCustomerName = extractParameter(String.class, 2, additionalInfo); | ||
129 | + metaData.putValue("assignedCustomerId", strCustomerId); | ||
130 | + metaData.putValue("assignedCustomerName", strCustomerName); | ||
131 | + } else if (actionType == ActionType.UNASSIGNED_FROM_CUSTOMER) { | ||
132 | + String strCustomerId = extractParameter(String.class, 1, additionalInfo); | ||
133 | + String strCustomerName = extractParameter(String.class, 2, additionalInfo); | ||
134 | + metaData.putValue("unassignedCustomerId", strCustomerId); | ||
135 | + metaData.putValue("unassignedCustomerName", strCustomerName); | ||
136 | + } else if (actionType == ActionType.ASSIGNED_FROM_TENANT) { | ||
137 | + String strTenantId = extractParameter(String.class, 0, additionalInfo); | ||
138 | + String strTenantName = extractParameter(String.class, 1, additionalInfo); | ||
139 | + metaData.putValue("assignedFromTenantId", strTenantId); | ||
140 | + metaData.putValue("assignedFromTenantName", strTenantName); | ||
141 | + } else if (actionType == ActionType.ASSIGNED_TO_TENANT) { | ||
142 | + String strTenantId = extractParameter(String.class, 0, additionalInfo); | ||
143 | + String strTenantName = extractParameter(String.class, 1, additionalInfo); | ||
144 | + metaData.putValue("assignedToTenantId", strTenantId); | ||
145 | + metaData.putValue("assignedToTenantName", strTenantName); | ||
146 | + } else if (actionType == ActionType.ASSIGNED_TO_EDGE) { | ||
147 | + String strEdgeId = extractParameter(String.class, 1, additionalInfo); | ||
148 | + String strEdgeName = extractParameter(String.class, 2, additionalInfo); | ||
149 | + metaData.putValue("assignedEdgeId", strEdgeId); | ||
150 | + metaData.putValue("assignedEdgeName", strEdgeName); | ||
151 | + } else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { | ||
152 | + String strEdgeId = extractParameter(String.class, 1, additionalInfo); | ||
153 | + String strEdgeName = extractParameter(String.class, 2, additionalInfo); | ||
154 | + metaData.putValue("unassignedEdgeId", strEdgeId); | ||
155 | + metaData.putValue("unassignedEdgeName", strEdgeName); | ||
156 | + } | ||
157 | + ObjectNode entityNode; | ||
158 | + if (entity != null) { | ||
159 | + entityNode = json.valueToTree(entity); | ||
160 | + if (entityId.getEntityType() == EntityType.DASHBOARD) { | ||
161 | + entityNode.put("configuration", ""); | ||
162 | + } | ||
163 | + } else { | ||
164 | + entityNode = json.createObjectNode(); | ||
165 | + if (actionType == ActionType.ATTRIBUTES_UPDATED) { | ||
166 | + String scope = extractParameter(String.class, 0, additionalInfo); | ||
167 | + @SuppressWarnings("unchecked") | ||
168 | + List<AttributeKvEntry> attributes = extractParameter(List.class, 1, additionalInfo); | ||
169 | + metaData.putValue(DataConstants.SCOPE, scope); | ||
170 | + if (attributes != null) { | ||
171 | + for (AttributeKvEntry attr : attributes) { | ||
172 | + addKvEntry(entityNode, attr); | ||
173 | + } | ||
174 | + } | ||
175 | + } else if (actionType == ActionType.ATTRIBUTES_DELETED) { | ||
176 | + String scope = extractParameter(String.class, 0, additionalInfo); | ||
177 | + @SuppressWarnings("unchecked") | ||
178 | + List<String> keys = extractParameter(List.class, 1, additionalInfo); | ||
179 | + metaData.putValue(DataConstants.SCOPE, scope); | ||
180 | + ArrayNode attrsArrayNode = entityNode.putArray("attributes"); | ||
181 | + if (keys != null) { | ||
182 | + keys.forEach(attrsArrayNode::add); | ||
183 | + } | ||
184 | + } else if (actionType == ActionType.TIMESERIES_UPDATED) { | ||
185 | + @SuppressWarnings("unchecked") | ||
186 | + List<TsKvEntry> timeseries = extractParameter(List.class, 0, additionalInfo); | ||
187 | + addTimeseries(entityNode, timeseries); | ||
188 | + } else if (actionType == ActionType.TIMESERIES_DELETED) { | ||
189 | + @SuppressWarnings("unchecked") | ||
190 | + List<String> keys = extractParameter(List.class, 0, additionalInfo); | ||
191 | + if (keys != null) { | ||
192 | + ArrayNode timeseriesArrayNode = entityNode.putArray("timeseries"); | ||
193 | + keys.forEach(timeseriesArrayNode::add); | ||
194 | + } | ||
195 | + entityNode.put("startTs", extractParameter(Long.class, 1, additionalInfo)); | ||
196 | + entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo)); | ||
197 | + } | ||
198 | + } | ||
199 | + TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); | ||
200 | + if (tenantId.isNullUid()) { | ||
201 | + if (entity instanceof HasTenantId) { | ||
202 | + tenantId = ((HasTenantId) entity).getTenantId(); | ||
203 | + } | ||
204 | + } | ||
205 | + tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); | ||
206 | + } catch (Exception e) { | ||
207 | + log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); | ||
208 | + } | ||
209 | + } | ||
210 | + } | ||
211 | + | ||
212 | + | ||
213 | + private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) { | ||
214 | + T result = null; | ||
215 | + if (additionalInfo != null && additionalInfo.length > index) { | ||
216 | + Object paramObject = additionalInfo[index]; | ||
217 | + if (clazz.isInstance(paramObject)) { | ||
218 | + result = clazz.cast(paramObject); | ||
219 | + } | ||
220 | + } | ||
221 | + return result; | ||
222 | + } | ||
223 | + | ||
224 | + private void addTimeseries(ObjectNode entityNode, List<TsKvEntry> timeseries) throws Exception { | ||
225 | + if (timeseries != null && !timeseries.isEmpty()) { | ||
226 | + ArrayNode result = entityNode.putArray("timeseries"); | ||
227 | + Map<Long, List<TsKvEntry>> groupedTelemetry = timeseries.stream() | ||
228 | + .collect(Collectors.groupingBy(TsKvEntry::getTs)); | ||
229 | + for (Map.Entry<Long, List<TsKvEntry>> entry : groupedTelemetry.entrySet()) { | ||
230 | + ObjectNode element = json.createObjectNode(); | ||
231 | + element.put("ts", entry.getKey()); | ||
232 | + ObjectNode values = element.putObject("values"); | ||
233 | + for (TsKvEntry tsKvEntry : entry.getValue()) { | ||
234 | + addKvEntry(values, tsKvEntry); | ||
235 | + } | ||
236 | + result.add(element); | ||
237 | + } | ||
238 | + } | ||
239 | + } | ||
240 | + | ||
241 | + private void addKvEntry(ObjectNode entityNode, KvEntry kvEntry) throws Exception { | ||
242 | + if (kvEntry.getDataType() == DataType.BOOLEAN) { | ||
243 | + kvEntry.getBooleanValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); | ||
244 | + } else if (kvEntry.getDataType() == DataType.DOUBLE) { | ||
245 | + kvEntry.getDoubleValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); | ||
246 | + } else if (kvEntry.getDataType() == DataType.LONG) { | ||
247 | + kvEntry.getLongValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); | ||
248 | + } else if (kvEntry.getDataType() == DataType.JSON) { | ||
249 | + if (kvEntry.getJsonValue().isPresent()) { | ||
250 | + entityNode.set(kvEntry.getKey(), json.readTree(kvEntry.getJsonValue().get())); | ||
251 | + } | ||
252 | + } else { | ||
253 | + entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString()); | ||
254 | + } | ||
255 | + } | ||
256 | +} |
@@ -17,9 +17,9 @@ package org.thingsboard.server.service.ttl; | @@ -17,9 +17,9 @@ package org.thingsboard.server.service.ttl; | ||
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.springframework.beans.factory.annotation.Value; | 19 | import org.springframework.beans.factory.annotation.Value; |
20 | -import org.thingsboard.server.dao.util.PsqlDao; | ||
21 | 20 | ||
22 | import java.sql.Connection; | 21 | import java.sql.Connection; |
22 | +import java.sql.DriverManager; | ||
23 | import java.sql.ResultSet; | 23 | import java.sql.ResultSet; |
24 | import java.sql.SQLException; | 24 | import java.sql.SQLException; |
25 | import java.sql.SQLWarning; | 25 | import java.sql.SQLWarning; |
@@ -62,4 +62,8 @@ public abstract class AbstractCleanUpService { | @@ -62,4 +62,8 @@ public abstract class AbstractCleanUpService { | ||
62 | 62 | ||
63 | protected abstract void doCleanUp(Connection connection) throws SQLException; | 63 | protected abstract void doCleanUp(Connection connection) throws SQLException; |
64 | 64 | ||
65 | + protected Connection getConnection() throws SQLException { | ||
66 | + return DriverManager.getConnection(dbUrl, dbUserName, dbPassword); | ||
67 | + } | ||
68 | + | ||
65 | } | 69 | } |
@@ -20,17 +20,27 @@ import lombok.extern.slf4j.Slf4j; | @@ -20,17 +20,27 @@ import lombok.extern.slf4j.Slf4j; | ||
20 | import org.springframework.beans.factory.annotation.Value; | 20 | import org.springframework.beans.factory.annotation.Value; |
21 | import org.springframework.scheduling.annotation.Scheduled; | 21 | import org.springframework.scheduling.annotation.Scheduled; |
22 | import org.springframework.stereotype.Service; | 22 | import org.springframework.stereotype.Service; |
23 | +import org.thingsboard.server.common.data.alarm.Alarm; | ||
24 | +import org.thingsboard.server.common.data.audit.ActionType; | ||
25 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
23 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
24 | import org.thingsboard.server.common.data.page.PageData; | 27 | import org.thingsboard.server.common.data.page.PageData; |
25 | import org.thingsboard.server.common.data.page.PageLink; | 28 | import org.thingsboard.server.common.data.page.PageLink; |
26 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | 29 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
27 | import org.thingsboard.server.common.msg.queue.ServiceType; | 30 | import org.thingsboard.server.common.msg.queue.ServiceType; |
28 | import org.thingsboard.server.dao.alarm.AlarmDao; | 31 | import org.thingsboard.server.dao.alarm.AlarmDao; |
32 | +import org.thingsboard.server.dao.alarm.AlarmService; | ||
33 | +import org.thingsboard.server.dao.relation.RelationService; | ||
29 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | 34 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
30 | import org.thingsboard.server.dao.tenant.TenantDao; | 35 | import org.thingsboard.server.dao.tenant.TenantDao; |
31 | import org.thingsboard.server.dao.util.PsqlDao; | 36 | import org.thingsboard.server.dao.util.PsqlDao; |
32 | import org.thingsboard.server.queue.discovery.PartitionService; | 37 | import org.thingsboard.server.queue.discovery.PartitionService; |
38 | +import org.thingsboard.server.service.action.RuleEngineEntityActionService; | ||
39 | +import org.thingsboard.server.service.ttl.AbstractCleanUpService; | ||
33 | 40 | ||
41 | +import java.sql.Connection; | ||
42 | +import java.sql.SQLException; | ||
43 | +import java.util.Date; | ||
34 | import java.util.Optional; | 44 | import java.util.Optional; |
35 | import java.util.UUID; | 45 | import java.util.UUID; |
36 | import java.util.concurrent.TimeUnit; | 46 | import java.util.concurrent.TimeUnit; |
@@ -43,37 +53,54 @@ public class AlarmsCleanUpService { | @@ -43,37 +53,54 @@ public class AlarmsCleanUpService { | ||
43 | @Value("${sql.ttl.alarms.removal_batch_size}") | 53 | @Value("${sql.ttl.alarms.removal_batch_size}") |
44 | private Integer removalBatchSize; | 54 | private Integer removalBatchSize; |
45 | 55 | ||
46 | - private final AlarmDao alarmDao; | ||
47 | private final TenantDao tenantDao; | 56 | private final TenantDao tenantDao; |
57 | + private final AlarmDao alarmDao; | ||
58 | + private final AlarmService alarmService; | ||
59 | + private final RelationService relationService; | ||
60 | + private final RuleEngineEntityActionService ruleEngineEntityActionService; | ||
48 | private final PartitionService partitionService; | 61 | private final PartitionService partitionService; |
49 | private final TbTenantProfileCache tenantProfileCache; | 62 | private final TbTenantProfileCache tenantProfileCache; |
50 | 63 | ||
51 | - @Scheduled(initialDelayString = "${sql.ttl.alarms.checking_interval}", fixedDelayString = "${sql.ttl.alarms.checking_interval}") | 64 | + @Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.alarms.checking_interval})}", fixedDelayString = "${sql.ttl.alarms.checking_interval}") |
52 | public void cleanUp() { | 65 | public void cleanUp() { |
53 | - PageLink tenantsBatchRequest = new PageLink(65536, 0); | ||
54 | - PageLink alarmsRemovalBatchRequest = new PageLink(removalBatchSize, 0); | ||
55 | - long currentTime = System.currentTimeMillis(); | ||
56 | - | 66 | + PageLink tenantsBatchRequest = new PageLink(10_000, 0); |
67 | + PageLink removalBatchRequest = new PageLink(removalBatchSize, 0); | ||
57 | PageData<TenantId> tenantsIds; | 68 | PageData<TenantId> tenantsIds; |
58 | do { | 69 | do { |
59 | tenantsIds = tenantDao.findTenantsIds(tenantsBatchRequest); | 70 | tenantsIds = tenantDao.findTenantsIds(tenantsBatchRequest); |
60 | - tenantsIds.getData().stream() | ||
61 | - .filter(tenantId -> partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) | ||
62 | - .forEach(tenantId -> { | ||
63 | - Optional<DefaultTenantProfileConfiguration> tenantProfileConfiguration = tenantProfileCache.get(tenantId).getProfileConfiguration(); | ||
64 | - if (tenantProfileConfiguration.isEmpty() || tenantProfileConfiguration.get().getAlarmsTtlDays() == 0) { | ||
65 | - return; | ||
66 | - } | 71 | + for (TenantId tenantId : tenantsIds.getData()) { |
72 | + if (!partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) { | ||
73 | + continue; | ||
74 | + } | ||
75 | + | ||
76 | + Optional<DefaultTenantProfileConfiguration> tenantProfileConfiguration = tenantProfileCache.get(tenantId).getProfileConfiguration(); | ||
77 | + if (tenantProfileConfiguration.isEmpty() || tenantProfileConfiguration.get().getAlarmsTtlDays() == 0) { | ||
78 | + continue; | ||
79 | + } | ||
67 | 80 | ||
68 | - PageData<UUID> toRemove; | ||
69 | - long outdatageTime = currentTime - TimeUnit.DAYS.toMillis(tenantProfileConfiguration.get().getAlarmsTtlDays()); | ||
70 | - log.info("Cleaning up outdated alarms for tenant {}", tenantId); | ||
71 | - do { | ||
72 | - toRemove = alarmDao.findAlarmsIdsByEndTsBeforeAndTenantId(outdatageTime, tenantId, alarmsRemovalBatchRequest); | ||
73 | - alarmDao.removeAllByIds(toRemove.getData()); | ||
74 | - } while (toRemove.hasNext()); | 81 | + long ttl = TimeUnit.DAYS.toMillis(tenantProfileConfiguration.get().getAlarmsTtlDays()); |
82 | + long outdatageTime = System.currentTimeMillis() - ttl; | ||
83 | + | ||
84 | + long totalRemoved = 0; | ||
85 | + while (true) { | ||
86 | + PageData<AlarmId> toRemove = alarmDao.findAlarmsIdsByEndTsBeforeAndTenantId(outdatageTime, tenantId, removalBatchRequest); | ||
87 | + toRemove.getData().forEach(alarmId -> { | ||
88 | + relationService.deleteEntityRelations(tenantId, alarmId); | ||
89 | + Alarm alarm = alarmService.deleteAlarm(tenantId, alarmId).getAlarm(); | ||
90 | + ruleEngineEntityActionService.pushEntityActionToRuleEngine(alarm.getOriginator(), alarm, tenantId, null, ActionType.ALARM_DELETE, null); | ||
75 | }); | 91 | }); |
76 | 92 | ||
93 | + totalRemoved += toRemove.getTotalElements(); | ||
94 | + if (!toRemove.hasNext()) { | ||
95 | + break; | ||
96 | + } | ||
97 | + } | ||
98 | + | ||
99 | + if (totalRemoved > 0) { | ||
100 | + log.info("Removed {} outdated alarm(s) for tenant {} older than {}", totalRemoved, tenantId, new Date(outdatageTime)); | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
77 | tenantsBatchRequest = tenantsBatchRequest.nextPageLink(); | 104 | tenantsBatchRequest = tenantsBatchRequest.nextPageLink(); |
78 | } while (tenantsIds.hasNext()); | 105 | } while (tenantsIds.hasNext()); |
79 | } | 106 | } |
@@ -40,7 +40,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { | @@ -40,7 +40,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { | ||
40 | @Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") | 40 | @Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") |
41 | public void cleanUp() { | 41 | public void cleanUp() { |
42 | if (ttlTaskExecutionEnabled) { | 42 | if (ttlTaskExecutionEnabled) { |
43 | - try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | 43 | + try (Connection conn = getConnection()) { |
44 | doCleanUp(conn); | 44 | doCleanUp(conn); |
45 | } catch (SQLException e) { | 45 | } catch (SQLException e) { |
46 | log.error("SQLException occurred during TTL task execution ", e); | 46 | log.error("SQLException occurred during TTL task execution ", e); |
@@ -43,7 +43,7 @@ public class EventsCleanUpService extends AbstractCleanUpService { | @@ -43,7 +43,7 @@ public class EventsCleanUpService extends AbstractCleanUpService { | ||
43 | @Scheduled(initialDelayString = "${sql.ttl.events.execution_interval_ms}", fixedDelayString = "${sql.ttl.events.execution_interval_ms}") | 43 | @Scheduled(initialDelayString = "${sql.ttl.events.execution_interval_ms}", fixedDelayString = "${sql.ttl.events.execution_interval_ms}") |
44 | public void cleanUp() { | 44 | public void cleanUp() { |
45 | if (ttlTaskExecutionEnabled) { | 45 | if (ttlTaskExecutionEnabled) { |
46 | - try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | 46 | + try (Connection conn = getConnection()) { |
47 | doCleanUp(conn); | 47 | doCleanUp(conn); |
48 | } catch (SQLException e) { | 48 | } catch (SQLException e) { |
49 | log.error("SQLException occurred during TTL task execution ", e); | 49 | log.error("SQLException occurred during TTL task execution ", e); |
@@ -36,7 +36,7 @@ public abstract class AbstractTimeseriesCleanUpService extends AbstractCleanUpSe | @@ -36,7 +36,7 @@ public abstract class AbstractTimeseriesCleanUpService extends AbstractCleanUpSe | ||
36 | @Scheduled(initialDelayString = "${sql.ttl.ts.execution_interval_ms}", fixedDelayString = "${sql.ttl.ts.execution_interval_ms}") | 36 | @Scheduled(initialDelayString = "${sql.ttl.ts.execution_interval_ms}", fixedDelayString = "${sql.ttl.ts.execution_interval_ms}") |
37 | public void cleanUp() { | 37 | public void cleanUp() { |
38 | if (ttlTaskExecutionEnabled) { | 38 | if (ttlTaskExecutionEnabled) { |
39 | - try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | 39 | + try (Connection conn = getConnection()) { |
40 | doCleanUp(conn); | 40 | doCleanUp(conn); |
41 | } catch (SQLException e) { | 41 | } catch (SQLException e) { |
42 | log.error("SQLException occurred during TTL task execution ", e); | 42 | log.error("SQLException occurred during TTL task execution ", e); |
@@ -275,7 +275,7 @@ sql: | @@ -275,7 +275,7 @@ sql: | ||
275 | edge_events_ttl: "${SQL_TTL_EDGE_EVENTS_TTL:2628000}" # Number of seconds. The current value corresponds to one month | 275 | edge_events_ttl: "${SQL_TTL_EDGE_EVENTS_TTL:2628000}" # Number of seconds. The current value corresponds to one month |
276 | alarms: | 276 | alarms: |
277 | checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours | 277 | checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours |
278 | - removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:200}" # To delete outdated alarms not all at once but in batches | 278 | + removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:3000}" # To delete outdated alarms not all at once but in batches |
279 | 279 | ||
280 | # Actor system parameters | 280 | # Actor system parameters |
281 | actors: | 281 | actors: |
@@ -66,6 +66,7 @@ public class DataConstants { | @@ -66,6 +66,7 @@ public class DataConstants { | ||
66 | public static final String TIMESERIES_DELETED = "TIMESERIES_DELETED"; | 66 | public static final String TIMESERIES_DELETED = "TIMESERIES_DELETED"; |
67 | public static final String ALARM_ACK = "ALARM_ACK"; | 67 | public static final String ALARM_ACK = "ALARM_ACK"; |
68 | public static final String ALARM_CLEAR = "ALARM_CLEAR"; | 68 | public static final String ALARM_CLEAR = "ALARM_CLEAR"; |
69 | + public static final String ALARM_DELETE = "ALARM_DELETE"; | ||
69 | public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; | 70 | public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; |
70 | public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT"; | 71 | public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT"; |
71 | public static final String PROVISION_SUCCESS = "PROVISION_SUCCESS"; | 72 | public static final String PROVISION_SUCCESS = "PROVISION_SUCCESS"; |
@@ -93,6 +93,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H | @@ -93,6 +93,7 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H | ||
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | + @JsonIgnore | ||
96 | public Optional<DefaultTenantProfileConfiguration> getProfileConfiguration() { | 97 | public Optional<DefaultTenantProfileConfiguration> getProfileConfiguration() { |
97 | return Optional.ofNullable(getProfileData().getConfiguration()) | 98 | return Optional.ofNullable(getProfileData().getConfiguration()) |
98 | .filter(profileConfiguration -> profileConfiguration instanceof DefaultTenantProfileConfiguration) | 99 | .filter(profileConfiguration -> profileConfiguration instanceof DefaultTenantProfileConfiguration) |
@@ -39,6 +39,7 @@ public enum ActionType { | @@ -39,6 +39,7 @@ public enum ActionType { | ||
39 | RELATIONS_DELETED(false), | 39 | RELATIONS_DELETED(false), |
40 | ALARM_ACK(false), | 40 | ALARM_ACK(false), |
41 | ALARM_CLEAR(false), | 41 | ALARM_CLEAR(false), |
42 | + ALARM_DELETE(false), | ||
42 | LOGIN(false), | 43 | LOGIN(false), |
43 | LOGOUT(false), | 44 | LOGOUT(false), |
44 | LOCKOUT(false), | 45 | LOCKOUT(false), |
@@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; | @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
22 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 22 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
23 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 23 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
24 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
24 | import org.thingsboard.server.common.data.id.CustomerId; | 25 | import org.thingsboard.server.common.data.id.CustomerId; |
25 | import org.thingsboard.server.common.data.id.EntityId; | 26 | import org.thingsboard.server.common.data.id.EntityId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -56,6 +57,6 @@ public interface AlarmDao extends Dao<Alarm> { | @@ -56,6 +57,6 @@ public interface AlarmDao extends Dao<Alarm> { | ||
56 | 57 | ||
57 | Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> status); | 58 | Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> status); |
58 | 59 | ||
59 | - PageData<UUID> findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); | 60 | + PageData<AlarmId> findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); |
60 | 61 | ||
61 | } | 62 | } |
@@ -23,6 +23,7 @@ import org.springframework.data.repository.CrudRepository; | @@ -23,6 +23,7 @@ import org.springframework.data.repository.CrudRepository; | ||
23 | import org.springframework.data.repository.query.Param; | 23 | import org.springframework.data.repository.query.Param; |
24 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 24 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
25 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 25 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
26 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | import org.thingsboard.server.dao.model.sql.AlarmEntity; | 27 | import org.thingsboard.server.dao.model.sql.AlarmEntity; |
27 | import org.thingsboard.server.dao.model.sql.AlarmInfoEntity; | 28 | import org.thingsboard.server.dao.model.sql.AlarmInfoEntity; |
28 | 29 | ||
@@ -161,7 +162,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> { | @@ -161,7 +162,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> { | ||
161 | @Param("affectedEntityType") String affectedEntityType, | 162 | @Param("affectedEntityType") String affectedEntityType, |
162 | @Param("alarmStatuses") Set<AlarmStatus> alarmStatuses); | 163 | @Param("alarmStatuses") Set<AlarmStatus> alarmStatuses); |
163 | 164 | ||
164 | - @Query("SELECT a.id FROM AlarmEntity a WHERE a.createdTime < :time AND a.endTs < :time") | ||
165 | - Page<UUID> findAlarmsIdsByEndTsBefore(@Param("time") Long time, Pageable pageable); | 165 | + @Query("SELECT a.id FROM AlarmEntity a WHERE a.tenantId = :tenantId AND a.createdTime < :time AND a.endTs < :time") |
166 | + Page<UUID> findAlarmsIdsByEndTsBeforeAndTenantId(@Param("time") Long time, @Param("tenantId") UUID tenantId, Pageable pageable); | ||
166 | 167 | ||
167 | } | 168 | } |
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; | @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
26 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 26 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
27 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 27 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
28 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 28 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
29 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
29 | import org.thingsboard.server.common.data.id.CustomerId; | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
30 | import org.thingsboard.server.common.data.id.EntityId; | 31 | import org.thingsboard.server.common.data.id.EntityId; |
31 | import org.thingsboard.server.common.data.id.TenantId; | 32 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -164,7 +165,8 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A | @@ -164,7 +165,8 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A | ||
164 | } | 165 | } |
165 | 166 | ||
166 | @Override | 167 | @Override |
167 | - public PageData<UUID> findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink) { | ||
168 | - return DaoUtil.pageToPageData(alarmRepository.findAlarmsIdsByEndTsBefore(time, DaoUtil.toPageable(pageLink))); | 168 | + public PageData<AlarmId> findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink) { |
169 | + return DaoUtil.pageToPageData(alarmRepository.findAlarmsIdsByEndTsBeforeAndTenantId(time, tenantId.getId(), DaoUtil.toPageable(pageLink))) | ||
170 | + .mapData(AlarmId::new); | ||
169 | } | 171 | } |
170 | } | 172 | } |
@@ -150,6 +150,8 @@ class DeviceState { | @@ -150,6 +150,8 @@ class DeviceState { | ||
150 | stateChanged = processAlarmClearNotification(ctx, msg); | 150 | stateChanged = processAlarmClearNotification(ctx, msg); |
151 | } else if (msg.getType().equals(DataConstants.ALARM_ACK)) { | 151 | } else if (msg.getType().equals(DataConstants.ALARM_ACK)) { |
152 | processAlarmAckNotification(ctx, msg); | 152 | processAlarmAckNotification(ctx, msg); |
153 | + } else if (msg.getType().equals(DataConstants.ALARM_DELETE)) { | ||
154 | + processAlarmDeleteNotification(ctx, msg); | ||
153 | } else { | 155 | } else { |
154 | if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED) || msg.getType().equals(DataConstants.ENTITY_UNASSIGNED)) { | 156 | if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED) || msg.getType().equals(DataConstants.ENTITY_UNASSIGNED)) { |
155 | dynamicPredicateValueCtx.resetCustomer(); | 157 | dynamicPredicateValueCtx.resetCustomer(); |
@@ -193,6 +195,12 @@ class DeviceState { | @@ -193,6 +195,12 @@ class DeviceState { | ||
193 | ctx.tellSuccess(msg); | 195 | ctx.tellSuccess(msg); |
194 | } | 196 | } |
195 | 197 | ||
198 | + private void processAlarmDeleteNotification(TbContext ctx, TbMsg msg) { | ||
199 | + Alarm alarm = JacksonUtil.fromString(msg.getData(), Alarm.class); | ||
200 | + alarmStates.values().removeIf(alarmState -> alarmState.getCurrentAlarm().getId().equals(alarm.getId())); | ||
201 | + ctx.tellSuccess(msg); | ||
202 | + } | ||
203 | + | ||
196 | private boolean processAttributesUpdateNotification(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { | 204 | private boolean processAttributesUpdateNotification(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { |
197 | String scope = msg.getMetaData().getValue(DataConstants.SCOPE); | 205 | String scope = msg.getMetaData().getValue(DataConstants.SCOPE); |
198 | if (StringUtils.isEmpty(scope)) { | 206 | if (StringUtils.isEmpty(scope)) { |