saveEdgeEvent(TenantId tenantId,
- EdgeId edgeId,
- EdgeEventType type,
- EdgeEventActionType action,
- EntityId entityId,
- JsonNode body) {
- log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
- tenantId, edgeId, type, action, entityId, body);
-
- EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
-
- return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
- clusterService.onEdgeEventUpdate(tenantId, edgeId);
- return null;
- }, dbCallBackExecutor);
- }
-
@Override
public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) {
log.debug("Pushing notification to edge {}", edgeNotificationMsg);
@@ -181,43 +157,43 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg);
break;
case ASSET:
- future = assetProcessor.processAssetNotification(tenantId, edgeNotificationMsg);
+ future = assetProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case DEVICE:
- future = deviceProcessor.processDeviceNotification(tenantId, edgeNotificationMsg);
+ future = deviceProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case ENTITY_VIEW:
- future = entityViewProcessor.processEntityViewNotification(tenantId, edgeNotificationMsg);
+ future = entityViewProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case DASHBOARD:
- future = dashboardProcessor.processDashboardNotification(tenantId, edgeNotificationMsg);
+ future = dashboardProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case RULE_CHAIN:
- future = ruleChainProcessor.processRuleChainNotification(tenantId, edgeNotificationMsg);
+ future = ruleChainProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case USER:
- future = userProcessor.processUserNotification(tenantId, edgeNotificationMsg);
+ future = userProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case CUSTOMER:
future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg);
break;
case DEVICE_PROFILE:
- future = deviceProfileProcessor.processDeviceProfileNotification(tenantId, edgeNotificationMsg);
+ future = deviceProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case ASSET_PROFILE:
- future = assetProfileProcessor.processAssetProfileNotification(tenantId, edgeNotificationMsg);
+ future = assetProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case OTA_PACKAGE:
- future = otaPackageProcessor.processOtaPackageNotification(tenantId, edgeNotificationMsg);
+ future = otaPackageProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case WIDGETS_BUNDLE:
- future = widgetBundleProcessor.processWidgetsBundleNotification(tenantId, edgeNotificationMsg);
+ future = widgetBundleProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case WIDGET_TYPE:
- future = widgetTypeProcessor.processWidgetTypeNotification(tenantId, edgeNotificationMsg);
+ future = widgetTypeProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case QUEUE:
- future = queueProcessor.processQueueNotification(tenantId, edgeNotificationMsg);
+ future = queueProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case ALARM:
future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg);
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java
new file mode 100644
index 0000000000..43b05094a4
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java
@@ -0,0 +1,158 @@
+/**
+ * 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;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.event.TransactionalEventListener;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.cluster.TbClusterService;
+import org.thingsboard.server.common.data.OtaPackageInfo;
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
+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.RuleChainType;
+import org.thingsboard.server.common.data.security.Authority;
+import org.thingsboard.server.dao.edge.EdgeSynchronizationManager;
+import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.RelationActionEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
+
+import javax.annotation.PostConstruct;
+
+import static org.thingsboard.server.service.entitiy.DefaultTbNotificationEntityService.edgeTypeByActionType;
+
+
+/**
+ * This event listener does not support async event processing because relay on ThreadLocal
+ * Another possible approach is to implement a special annotation and a bunch of classes similar to TransactionalApplicationListener
+ * This class is the simplest approach to maintain edge synchronization within the single class.
+ *
+ * For async event publishers, you have to decide whether publish event on creating async task in the same thread where dao method called
+ * @Autowired
+ * EdgeEventSynchronizationManager edgeSynchronizationManager
+ * ...
+ * //some async write action make future
+ * if (!edgeSynchronizationManager.isSync()) {
+ * future.addCallback(eventPublisher.publishEvent(...))
+ * }
+ * */
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class EdgeEventSourcingListener {
+
+ private final TbClusterService tbClusterService;
+ private final EdgeSynchronizationManager edgeSynchronizationManager;
+
+ @PostConstruct
+ public void init() {
+ log.info("EdgeEventSourcingListener initiated");
+ }
+
+ @TransactionalEventListener(fallbackExecution = true)
+ public void handleEvent(SaveEntityEvent> event) {
+ if (edgeSynchronizationManager.isSync()) {
+ return;
+ }
+ try {
+ if (!isValidEdgeEventEntity(event.getEntity())) {
+ return;
+ }
+ log.trace("[{}] SaveEntityEvent called: {}", event.getTenantId(), event);
+ EdgeEventActionType action = Boolean.TRUE.equals(event.getAdded()) ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED;
+ tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), null, event.getEntityId(),
+ null, null, action);
+ } catch (Exception e) {
+ log.error("[{}] failed to process SaveEntityEvent: {}", event.getTenantId(), event);
+ }
+ }
+
+ @TransactionalEventListener(fallbackExecution = true)
+ public void handleEvent(DeleteEntityEvent> event) {
+ if (edgeSynchronizationManager.isSync()) {
+ return;
+ }
+ try {
+ log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event);
+ tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(),
+ JacksonUtil.toString(event.getEntity()), null, EdgeEventActionType.DELETED);
+ } catch (Exception e) {
+ log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event);
+ }
+ }
+
+ @TransactionalEventListener(fallbackExecution = true)
+ public void handleEvent(ActionEntityEvent event) {
+ if (edgeSynchronizationManager.isSync()) {
+ return;
+ }
+ try {
+ log.trace("[{}] ActionEntityEvent called: {}", event.getTenantId(), event);
+ tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(),
+ event.getBody(), null, edgeTypeByActionType(event.getActionType()));
+ } catch (Exception e) {
+ log.error("[{}] failed to process ActionEntityEvent: {}", event.getTenantId(), event);
+ }
+ }
+
+ @TransactionalEventListener(fallbackExecution = true)
+ public void handleEvent(RelationActionEvent event) {
+ if (edgeSynchronizationManager.isSync()) {
+ return;
+ }
+ try {
+ EntityRelation relation = event.getRelation();
+ if (relation == null) {
+ log.trace("[{}] skipping RelationActionEvent event in case relation is null: {}", event.getTenantId(), event);
+ return;
+ }
+ if (!RelationTypeGroup.COMMON.equals(relation.getTypeGroup())) {
+ log.trace("[{}] skipping RelationActionEvent event in case NOT COMMON relation type group: {}", event.getTenantId(), event);
+ return;
+ }
+ log.trace("[{}] RelationActionEvent called: {}", event.getTenantId(), event);
+ tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), null, null,
+ JacksonUtil.toString(relation), EdgeEventType.RELATION, edgeTypeByActionType(event.getActionType()));
+ } catch (Exception e) {
+ log.error("[{}] failed to process RelationActionEvent: {}", event.getTenantId(), event);
+ }
+ }
+
+ private boolean isValidEdgeEventEntity(Object entity) {
+ if (entity instanceof OtaPackageInfo) {
+ OtaPackageInfo otaPackageInfo = (OtaPackageInfo) entity;
+ return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData();
+ } else if (entity instanceof RuleChain) {
+ RuleChain ruleChain = (RuleChain) entity;
+ return RuleChainType.EDGE.equals(ruleChain.getType());
+ } else if (entity instanceof User) {
+ User user = (User) entity;
+ return !Authority.SYS_ADMIN.equals(user.getAuthority());
+ } else if (entity instanceof AlarmApiCallResult) {
+ AlarmApiCallResult alarmApiCallResult = (AlarmApiCallResult) entity;
+ return alarmApiCallResult.isModified();
+ }
+ // Default: If the entity doesn't match any of the conditions, consider it as valid.
+ return true;
+ }
+}
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 e7214177d2..d002854155 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
@@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
+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;
@@ -71,10 +72,6 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
-import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT;
-import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT;
-import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE;
-
@Service
@Slf4j
@ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true")
@@ -278,7 +275,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
long lastConnectTs = System.currentTimeMillis();
save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs);
- pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, CONNECT_EVENT);
+ pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, TbMsgType.CONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
scheduleEdgeEventsCheck(edgeGrpcSession);
}
@@ -398,7 +395,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);
long lastDisconnectTs = System.currentTimeMillis();
save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs);
- pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT);
+ pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, TbMsgType.DISCONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
} else {
log.debug("[{}] edge session [{}] is not available anymore, nothing to remove. most probably this session is already outdated!", edgeId, sessionId);
@@ -451,10 +448,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
}
}
- private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, String msgType) {
+ private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, TbMsgType msgType) {
try {
ObjectNode edgeState = JacksonUtil.newObjectNode();
- if (msgType.equals(CONNECT_EVENT)) {
+ if (msgType.equals(TbMsgType.CONNECT_EVENT)) {
edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, true);
edgeState.put(DefaultDeviceStateService.LAST_CONNECT_TIME, ts);
} else {
@@ -464,7 +461,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
String data = JacksonUtil.toString(edgeState);
TbMsgMetaData md = new TbMsgMetaData();
if (!persistToTelemetry) {
- md.putValue(DataConstants.SCOPE, SERVER_SCOPE);
+ md.putValue(DataConstants.SCOPE, DataConstants.SERVER_SCOPE);
}
TbMsg tbMsg = TbMsg.newMsg(msgType, edgeId, md, TbMsgDataType.JSON, data);
clusterService.pushMsgToRuleEngine(tenantId, edgeId, tbMsg, null);
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 ac7c791338..56f4f06fa3 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
@@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
+import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils;
@@ -55,6 +56,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
+import org.thingsboard.server.dao.edge.EdgeSynchronizationManager;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService;
@@ -249,15 +251,18 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected QueueMsgConstructor queueMsgConstructor;
+ @Autowired
+ protected EdgeSynchronizationManager edgeSynchronizationManager;
+
@Autowired
protected DbCallbackExecutorService dbCallbackExecutorService;
protected ListenableFuture saveEdgeEvent(TenantId tenantId,
- EdgeId edgeId,
- EdgeEventType type,
- EdgeEventActionType action,
- EntityId entityId,
- JsonNode body) {
+ EdgeId edgeId,
+ EdgeEventType type,
+ EdgeEventActionType action,
+ EntityId entityId,
+ JsonNode body) {
log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " +
"action [{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);
@@ -288,7 +293,7 @@ public abstract class BaseEdgeProcessor {
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
- protected List> processActionForAllEdgesByTenantId(TenantId tenantId,
+ private List> processActionForAllEdgesByTenantId(TenantId tenantId,
EdgeEventType type,
EdgeEventActionType actionType,
EntityId entityId,
@@ -340,36 +345,46 @@ public abstract class BaseEdgeProcessor {
}
}
- protected ListenableFuture processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
+ public ListenableFuture processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
- EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type,
- new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
- EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg);
- switch (actionType) {
- case ADDED:
- case UPDATED:
- case CREDENTIALS_UPDATED:
- case ASSIGNED_TO_CUSTOMER:
- case UNASSIGNED_FROM_CUSTOMER:
- case DELETED:
- if (edgeId != null) {
- return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
- } else {
- return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
- }
- case ASSIGNED_TO_EDGE:
- case UNASSIGNED_FROM_EDGE:
- ListenableFuture future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
- return Futures.transformAsync(future, unused -> {
- if (type.equals(EdgeEventType.RULE_CHAIN)) {
- return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId);
+ EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
+ EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
+ if (type.isAllEdgesRelated()) {
+ return processEntityNotificationForAllEdges(tenantId, type, actionType, entityId);
+ } else {
+ JsonNode body = JacksonUtil.toJsonNode(edgeNotificationMsg.getBody());
+ EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg);
+ switch (actionType) {
+ case UPDATED:
+ case CREDENTIALS_UPDATED:
+ case ASSIGNED_TO_CUSTOMER:
+ case UNASSIGNED_FROM_CUSTOMER:
+ if (edgeId != null) {
+ return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, body);
} else {
- return Futures.immediateFuture(null);
+ return processNotificationToRelatedEdges(tenantId, entityId, type, actionType);
}
- }, dbCallbackExecutorService);
- default:
- return Futures.immediateFuture(null);
+ case DELETED:
+ EdgeEventActionType deleted = EdgeEventActionType.DELETED;
+ if (edgeId != null) {
+ return saveEdgeEvent(tenantId, edgeId, type, deleted, entityId, body);
+ } else {
+ return Futures.transform(Futures.allAsList(processActionForAllEdgesByTenantId(tenantId, type, deleted, entityId, body)),
+ voids -> null, dbCallbackExecutorService);
+ }
+ case ASSIGNED_TO_EDGE:
+ case UNASSIGNED_FROM_EDGE:
+ ListenableFuture future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, body);
+ return Futures.transformAsync(future, unused -> {
+ if (type.equals(EdgeEventType.RULE_CHAIN)) {
+ return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId);
+ } else {
+ return Futures.immediateFuture(null);
+ }
+ }, dbCallbackExecutorService);
+ default:
+ return Futures.immediateFuture(null);
+ }
}
}
@@ -381,7 +396,7 @@ public abstract class BaseEdgeProcessor {
}
}
- private ListenableFuture pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) {
+ private ListenableFuture processNotificationToRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData pageData;
List> futures = new ArrayList<>();
@@ -432,10 +447,7 @@ public abstract class BaseEdgeProcessor {
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
- protected ListenableFuture processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
- EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
- EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
+ private ListenableFuture processEntityNotificationForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) {
switch (actionType) {
case ADDED:
case UPDATED:
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java
index 189d69e68d..0b86352c02 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.service.edge.rpc.processor.alarm;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
@@ -28,6 +29,7 @@ import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AlarmId;
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.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@@ -62,9 +64,9 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor {
AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
switch (actionType) {
case DELETED:
- EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
Alarm deletedAlarm = JacksonUtil.OBJECT_MAPPER.readValue(edgeNotificationMsg.getBody(), Alarm.class);
- return saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, JacksonUtil.OBJECT_MAPPER.valueToTree(deletedAlarm));
+ List> delFutures = pushEventToAllRelatedEdges(tenantId, deletedAlarm.getOriginator(), alarmId, actionType, JacksonUtil.OBJECT_MAPPER.valueToTree(deletedAlarm));
+ return Futures.transform(Futures.allAsList(delFutures), voids -> null, dbCallbackExecutorService);
default:
ListenableFuture alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
return Futures.transformAsync(alarmFuture, alarm -> {
@@ -75,28 +77,33 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor {
if (type == null) {
return Futures.immediateFuture(null);
}
- PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
- PageData pageData;
- List> futures = new ArrayList<>();
- do {
- pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);
- if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
- for (EdgeId relatedEdgeId : pageData.getData()) {
- futures.add(saveEdgeEvent(tenantId,
- relatedEdgeId,
- EdgeEventType.ALARM,
- EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
- alarmId,
- null));
- }
- if (pageData.hasNext()) {
- pageLink = pageLink.nextPageLink();
- }
- }
- } while (pageData != null && pageData.hasNext());
+ List> futures = pushEventToAllRelatedEdges(tenantId, alarm.getOriginator(), alarmId, actionType, null);
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}, dbCallbackExecutorService);
}
}
+ private List> pushEventToAllRelatedEdges(TenantId tenantId, EntityId originatorId, AlarmId alarmId, EdgeEventActionType actionType, JsonNode body) {
+ PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
+ PageData pageData;
+ List> futures = new ArrayList<>();
+ do {
+ pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, originatorId, pageLink);
+ if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
+ for (EdgeId relatedEdgeId : pageData.getData()) {
+ futures.add(saveEdgeEvent(tenantId,
+ relatedEdgeId,
+ EdgeEventType.ALARM,
+ actionType,
+ alarmId,
+ body));
+ }
+ if (pageData.hasNext()) {
+ pageLink = pageLink.nextPageLink();
+ }
+ }
+ } while (pageData != null && pageData.hasNext());
+ return futures;
+ }
+
}
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 be64f475a2..fbe141ab32 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
@@ -49,6 +49,7 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
return Futures.immediateFuture(null);
}
try {
+ edgeSynchronizationManager.getSync().set(true);
switch (alarmUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
@@ -72,26 +73,26 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
} else {
alarmService.updateAlarm(AlarmUpdateRequest.fromAlarm(alarm));
}
- return Futures.immediateFuture(null);
+ break;
case ALARM_ACK_RPC_MESSAGE:
Alarm alarmToAck = alarmService.findAlarmById(tenantId, alarmId);
if (alarmToAck != null) {
alarmService.acknowledgeAlarm(tenantId, alarmId, alarmUpdateMsg.getAckTs());
}
- return Futures.immediateFuture(null);
+ break;
case ALARM_CLEAR_RPC_MESSAGE:
Alarm alarmToClear = alarmService.findAlarmById(tenantId, alarmId);
if (alarmToClear != null) {
alarmService.clearAlarm(tenantId, alarmId, alarmUpdateMsg.getClearTs(),
JacksonUtil.OBJECT_MAPPER.readTree(alarmUpdateMsg.getDetails()));
}
- return Futures.immediateFuture(null);
+ break;
case ENTITY_DELETED_RPC_MESSAGE:
Alarm alarmToDelete = alarmService.findAlarmById(tenantId, alarmId);
if (alarmToDelete != null) {
alarmService.delAlarm(tenantId, alarmId);
}
- return Futures.immediateFuture(null);
+ break;
case UNRECOGNIZED:
default:
return handleUnsupportedMsgType(alarmUpdateMsg.getMsgType());
@@ -99,7 +100,10 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
} catch (Exception e) {
log.error("[{}] Failed to process alarm update msg [{}]", tenantId, alarmUpdateMsg, e);
return Futures.immediateFailedFuture(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
+ return Futures.immediateFuture(null);
}
private EntityId getAlarmOriginator(TenantId tenantId, String entityName, EntityType entityType) {
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 2fb7320219..d7824a7467 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,7 +15,6 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.asset;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
@@ -23,11 +22,9 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.AssetId;
-import org.thingsboard.server.common.data.id.TenantId;
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.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -72,8 +69,4 @@ public class AssetEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processAssetNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotification(tenantId, edgeNotificationMsg);
- }
}
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 51c42e5764..ec0e0b9761 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,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.asset;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.AssetProfileId;
-import org.thingsboard.server.common.data.id.TenantId;
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.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -63,9 +60,4 @@ public class AssetProfileEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processAssetProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
-
}
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 9651609bd3..14f566db0a 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,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.dashboard;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.DashboardId;
-import org.thingsboard.server.common.data.id.TenantId;
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.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -67,8 +64,4 @@ public class DashboardEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processDashboardNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotification(tenantId, edgeNotificationMsg);
- }
}
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 742acdbcda..1421cf32c0 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
@@ -97,7 +97,7 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
deviceCredentials.setCredentialsId(StringUtils.randomAlphanumeric(20));
deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
}
- tbClusterService.onDeviceUpdated(savedDevice, created ? null : device, false);
+ tbClusterService.onDeviceUpdated(savedDevice, created ? null : device);
} finally {
deviceCreationLock.unlock();
}
@@ -113,6 +113,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue());
try {
+ edgeSynchronizationManager.getSync().set(true);
+
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType()));
deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId());
@@ -123,6 +125,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]",
device.getName(), deviceCredentialsUpdateMsg, e);
throw new RuntimeException(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
} else {
log.warn("Can't find device by id [{}], deviceCredentialsUpdateMsg [{}]", deviceId, deviceCredentialsUpdateMsg);
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 3e617de8c6..d083c5b16f 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
@@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
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.msg.TbMsgType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rpc.RpcError;
@@ -46,7 +47,6 @@ 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.common.msg.rpc.FromDeviceRpcResponse;
-import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsUpdateMsg;
@@ -54,7 +54,6 @@ import org.thingsboard.server.gen.edge.v1.DeviceRpcCallMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
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.util.TbCoreComponent;
@@ -71,6 +70,8 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
log.trace("[{}] executing processDeviceMsgFromEdge [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
try {
+ edgeSynchronizationManager.getSync().set(true);
+
switch (deviceUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
@@ -93,6 +94,8 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
} else {
return Futures.immediateFailedFuture(e);
}
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
}
@@ -124,7 +127,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
try {
Device device = deviceService.findDeviceById(tenantId, deviceId);
ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device);
- TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, device.getCustomerId(),
+ 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
@@ -138,7 +141,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
}
});
} catch (JsonProcessingException | IllegalArgumentException e) {
- log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, DataConstants.ENTITY_CREATED, e);
+ log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, TbMsgType.ENTITY_CREATED.name(), e);
}
}
@@ -216,7 +219,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
ObjectNode data = JacksonUtil.newObjectNode();
data.put("method", deviceRpcCallMsg.getRequestMsg().getMethod());
data.put("params", deviceRpcCallMsg.getRequestMsg().getParams());
- TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, null, metaData,
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, deviceId, null, metaData,
TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(data));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
@Override
@@ -308,8 +311,4 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
.addDeviceCredentialsRequestMsg(deviceCredentialsRequestMsg);
return builder.build();
}
-
- public ListenableFuture processDeviceNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotification(tenantId, edgeNotificationMsg);
- }
}
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 5ddfecfdb1..c888ec2925 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,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.device;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.DeviceProfileId;
-import org.thingsboard.server.common.data.id.TenantId;
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.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -63,8 +60,4 @@ public class DeviceProfileEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processDeviceProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
}
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 29965fcc69..0964a434ba 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,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.entityview;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.EntityViewId;
-import org.thingsboard.server.common.data.id.TenantId;
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.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -67,8 +64,4 @@ public class EntityViewEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processEntityViewNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotification(tenantId, edgeNotificationMsg);
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java
index 8206e0f1b0..fae6399e3a 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java
@@ -15,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.ota;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.OtaPackageId;
-import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -63,8 +60,4 @@ public class OtaPackageEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processOtaPackageNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java
index cbacaf9276..8562582940 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java
@@ -15,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.queue;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.QueueId;
-import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -64,7 +61,4 @@ public class QueueEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public ListenableFuture processQueueNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
}
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 df683bbbe2..9038cc9c33 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
@@ -34,8 +34,9 @@ import java.util.UUID;
public abstract class BaseRelationProcessor extends BaseEdgeProcessor {
public ListenableFuture processRelationMsg(TenantId tenantId, RelationUpdateMsg relationUpdateMsg) {
- log.trace("[{}] processRelationFromEdge [{}]", tenantId, relationUpdateMsg);
+ log.trace("[{}] processRelationMsg [{}]", tenantId, relationUpdateMsg);
try {
+ edgeSynchronizationManager.getSync().set(true);
EntityRelation entityRelation = new EntityRelation();
UUID fromUUID = new UUID(relationUpdateMsg.getFromIdMSB(), relationUpdateMsg.getFromIdLSB());
@@ -55,15 +56,15 @@ public abstract class BaseRelationProcessor extends BaseEdgeProcessor {
case ENTITY_UPDATED_RPC_MESSAGE:
if (isEntityExists(tenantId, entityRelation.getTo())
&& isEntityExists(tenantId, entityRelation.getFrom())) {
- return Futures.transform(relationService.saveRelationAsync(tenantId, entityRelation),
- (result) -> null, dbCallbackExecutorService);
+ relationService.saveRelation(tenantId, entityRelation);
+ break;
} else {
log.warn("Skipping relating update msg because from/to entity doesn't exists on edge, {}", relationUpdateMsg);
- return Futures.immediateFuture(null);
+ break;
}
case ENTITY_DELETED_RPC_MESSAGE:
- return Futures.transform(relationService.deleteRelationAsync(tenantId, entityRelation),
- (result) -> null, dbCallbackExecutorService);
+ relationService.deleteRelation(tenantId, entityRelation);
+ break;
case UNRECOGNIZED:
default:
return handleUnsupportedMsgType(relationUpdateMsg.getMsgType());
@@ -71,6 +72,9 @@ public abstract class BaseRelationProcessor extends BaseEdgeProcessor {
} catch (Exception e) {
log.error("[{}] Failed to process relation update msg [{}]", tenantId, relationUpdateMsg, e);
return Futures.immediateFailedFuture(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
+ return Futures.immediateFuture(null);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java
index 69d4f7ef64..ba6fc1ef97 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java
@@ -15,13 +15,11 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.rule;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.RuleChainId;
-import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@@ -29,7 +27,6 @@ import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -93,8 +90,4 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processRuleChainNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotification(tenantId, edgeNotificationMsg);
- }
}
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 fece86b92a..5942628bf3 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
@@ -50,11 +50,11 @@ 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.kv.AttributeKvEntry;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
-import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.dao.model.ModelConstants;
@@ -184,7 +184,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + "");
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
- TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
+ TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_TELEMETRY_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -228,7 +228,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
SettableFuture futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
- TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
+ TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -257,7 +257,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onSuccess(@Nullable Void tmp) {
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
- TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId,
+ TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.ATTRIBUTES_UPDATED, entityId,
customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java
index 9070686fd6..de40fdb1a3 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java
@@ -15,19 +15,16 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.user;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.EdgeEvent;
-import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -67,11 +64,9 @@ public class UserEdgeProcessor extends BaseEdgeProcessor {
.addUserCredentialsUpdateMsg(userCredentialsUpdateMsg)
.build();
}
+ break;
}
return downlinkMsg;
}
- public ListenableFuture processUserNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java
index a429816a31..d50e752fdf 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java
@@ -15,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.widget;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
-import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -63,8 +60,4 @@ public class WidgetBundleEdgeProcessor extends BaseEdgeProcessor {
}
return downlinkMsg;
}
-
- public ListenableFuture processWidgetsBundleNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java
index 3caad57081..5171724439 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java
@@ -15,18 +15,15 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.widget;
-import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
-import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetTypeId;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@@ -64,7 +61,4 @@ public class WidgetTypeEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public ListenableFuture processWidgetTypeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
index 0a75404fb4..f2465c9398 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
@@ -21,29 +21,21 @@ import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.cluster.TbClusterService;
-import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
-import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
-import org.thingsboard.server.common.data.alarm.Alarm;
-import org.thingsboard.server.common.data.alarm.AlarmComment;
-import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
-import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
-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.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.relation.EntityRelation;
-import org.thingsboard.server.common.data.rule.RuleChain;
-import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
@@ -51,8 +43,6 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
-import java.util.List;
-
@Slf4j
@Service
@RequiredArgsConstructor
@@ -98,54 +88,6 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
}
}
- @Override
- public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
- CustomerId customerId, ActionType actionType,
- List relatedEdgeIds,
- User user, Object... additionalInfo) {
- logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
- sendDeleteNotificationMsg(tenantId, entityId, relatedEdgeIds, null);
- }
-
- @Override
- public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId,
- List relatedEdgeIds, User user, String body, Object... additionalInfo) {
- logEntityAction(tenantId, originatorId, alarm, customerId, ActionType.DELETED, user, additionalInfo);
- sendAlarmDeleteNotificationMsg(tenantId, alarm, relatedEdgeIds, body);
- }
-
- @Override
- public void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, List relatedEdgeIds, User user) {
- RuleChainId ruleChainId = ruleChain.getId();
- logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, null, ruleChainId.toString());
- if (RuleChainType.EDGE.equals(ruleChain.getType())) {
- sendDeleteNotificationMsg(tenantId, ruleChainId, relatedEdgeIds, null);
- }
- }
-
- @Override
- public void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType) {
- sendEntityNotificationMsg(tenantId, entityId, edgeEventActionType);
- }
-
- @Override
- public void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
- CustomerId customerId, E entity,
- ActionType actionType,
- User user, Object... additionalInfo) {
- logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
- sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType), JacksonUtil.toString(customerId));
- }
-
- @Override
- public void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
- CustomerId customerId, EdgeId edgeId,
- E entity, ActionType actionType,
- User user, Object... additionalInfo) {
- logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
- sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeTypeByActionType(actionType));
- }
-
@Override
public void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) {
tbClusterService.onTenantChange(tenant, null);
@@ -168,18 +110,16 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override
public void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
- List relatedEdgeIds, User user, Object... additionalInfo) {
+ User user, Object... additionalInfo) {
gatewayNotificationsService.onDeviceDeleted(device);
tbClusterService.onDeviceDeleted(device, null);
-
- notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user, additionalInfo);
+ logEntityAction(tenantId, deviceId, device, customerId, ActionType.DELETED, user, additionalInfo);
}
@Override
public void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
DeviceCredentials deviceCredentials, User user) {
tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceCredentials.getDeviceId(), deviceCredentials), null);
- sendEntityNotificationMsg(tenantId, deviceId, EdgeEventActionType.CREDENTIALS_UPDATED);
logEntityAction(tenantId, deviceId, device, customerId, ActionType.CREDENTIALS_UPDATED, user, deviceCredentials);
}
@@ -190,16 +130,6 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
pushAssignedFromNotification(tenant, newTenantId, device);
}
- @Override
- public void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity,
- CustomerId customerId, ActionType actionType,
- User user, Object... additionalInfo) {
- logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
- if (actionType == ActionType.UPDATED) {
- sendEntityNotificationMsg(tenantId, entityId, EdgeEventActionType.UPDATED);
- }
- }
-
@Override
public void notifyCreateOrUpdateOrDeleteEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge,
ActionType actionType, User user, Object... additionalInfo) {
@@ -222,71 +152,16 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
}
@Override
- public void notifyCreateOrUpdateAlarm(AlarmInfo alarm, ActionType actionType, User user, Object... additionalInfo) {
- logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo);
- sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType));
- }
-
- @Override
- public void notifyAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user) {
- logEntityAction(alarm.getTenantId(), alarm.getId(), alarm, alarm.getCustomerId(), actionType, user, alarmComment);
- }
-
- @Override
- public void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId,
- I entityId, E entity, User user,
- ActionType actionType, boolean sendNotifyMsgToEdge, Exception e,
- Object... additionalInfo) {
- logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo);
- if (sendNotifyMsgToEdge) {
- sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType));
- }
- }
-
- @Override
- public void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
- ActionType actionType, Object... additionalInfo) {
- logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, additionalInfo);
- logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, additionalInfo);
- if (!EntityType.EDGE.equals(relation.getFrom().getEntityType()) && !EntityType.EDGE.equals(relation.getTo().getEntityType())) {
- sendNotificationMsgToEdge(tenantId, null, null, JacksonUtil.toString(relation),
- EdgeEventType.RELATION, edgeTypeByActionType(actionType));
- }
- }
-
- private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) {
- sendEntityNotificationMsg(tenantId, entityId, action, null);
- }
-
- private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action, String body) {
- sendNotificationMsgToEdge(tenantId, null, entityId, body, null, action);
- }
-
- private void sendAlarmDeleteNotificationMsg(TenantId tenantId, Alarm alarm, List edgeIds, String body) {
- sendDeleteNotificationMsg(tenantId, alarm.getId(), edgeIds, body);
- }
-
- private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List edgeIds, String body) {
- if (edgeIds != null && !edgeIds.isEmpty()) {
- for (EdgeId edgeId : edgeIds) {
- sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED);
- }
- }
- }
-
- private void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) {
- sendNotificationMsgToEdge(tenantId, edgeId, entityId, null, null, action);
- }
-
- private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body,
- EdgeEventType type, EdgeEventActionType action) {
- tbClusterService.sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, type, action);
+ public void logEntityRelationAction(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
+ ActionType actionType, Exception e, Object... additionalInfo) {
+ logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, e, additionalInfo);
+ logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, e, additionalInfo);
}
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
if (data != null) {
- TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(),
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(),
assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
}
@@ -327,6 +202,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
return EdgeEventActionType.ASSIGNED_TO_EDGE;
case UNASSIGNED_FROM_EDGE:
return EdgeEventActionType.UNASSIGNED_FROM_EDGE;
+ case CREDENTIALS_UPDATED:
+ return EdgeEventActionType.CREDENTIALS_UPDATED;
default:
return null;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
index c5f8f85831..d14b2c6293 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
@@ -19,12 +19,8 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
-import org.thingsboard.server.common.data.alarm.Alarm;
-import org.thingsboard.server.common.data.alarm.AlarmComment;
-import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
@@ -32,11 +28,8 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.relation.EntityRelation;
-import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.security.DeviceCredentials;
-import java.util.List;
-
public interface TbNotificationEntityService {
void logEntityAction(TenantId tenantId, I entityId, ActionType actionType, User user,
@@ -55,33 +48,6 @@ public interface TbNotificationEntityService {
ActionType actionType, User user, Exception e,
Object... additionalInfo);
- void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity,
- CustomerId customerId, ActionType actionType,
- User user, Object... additionalInfo);
-
- void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
- CustomerId customerId, ActionType actionType,
- List relatedEdgeIds,
- User user, Object... additionalInfo);
-
- void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId,
- List relatedEdgeIds, User user, String body, Object... additionalInfo);
-
- void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain,
- List relatedEdgeIds, User user);
-
- void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType);
-
- void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
- CustomerId customerId, E entity,
- ActionType actionType,
- User user, Object... additionalInfo);
-
- void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
- CustomerId customerId, EdgeId edgeId,
- E entity, ActionType actionType,
- User user, Object... additionalInfo);
-
void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event);
void notifyDeleteTenant(Tenant tenant);
@@ -90,7 +56,7 @@ public interface TbNotificationEntityService {
Device oldDevice, ActionType actionType, User user, Object... additionalInfo);
void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
- List relatedEdgeIds, User user, Object... additionalInfo);
+ User user, Object... additionalInfo);
void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
DeviceCredentials deviceCredentials, User user);
@@ -101,16 +67,6 @@ public interface TbNotificationEntityService {
void notifyCreateOrUpdateOrDeleteEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType,
User user, Object... additionalInfo);
- void notifyCreateOrUpdateAlarm(AlarmInfo alarm, ActionType actionType, User user, Object... additionalInfo);
-
- void notifyAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user);
-
-
- void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId,
- I entityId, E entity, User user,
- ActionType actionType, boolean sendNotifyMsgToEdge,
- Exception e, Object... additionalInfo);
-
- void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
- ActionType actionType, Object... additionalInfo);
+ void logEntityRelationAction(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
+ ActionType actionType, Exception e, Object... additionalInfo);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java
index 6dfc81c747..282d11ab2a 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java
@@ -45,7 +45,8 @@ public class DefaultTbAlarmCommentService extends AbstractTbEntityService implem
}
try {
AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment));
- notificationEntityService.notifyAlarmComment(alarm, savedAlarmComment, actionType, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getId(), alarm, alarm.getCustomerId(), actionType, user, savedAlarmComment);
+
return savedAlarmComment;
} catch (Exception e) {
notificationEntityService.logEntityAction(alarm.getTenantId(), emptyId(EntityType.ALARM), alarm, actionType, user, e, alarmComment);
@@ -62,7 +63,7 @@ public class DefaultTbAlarmCommentService extends AbstractTbEntityService implem
String.format("User %s deleted his comment",
(user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())));
AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.saveAlarmComment(alarm.getTenantId(), alarmComment));
- notificationEntityService.notifyAlarmComment(alarm, savedAlarmComment, ActionType.DELETED_COMMENT, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getId(), alarm, alarm.getCustomerId(), ActionType.DELETED_COMMENT, user, savedAlarmComment);
} else {
throw new ThingsboardException("System comment could not be deleted", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
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..e776c040c0 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
@@ -67,10 +67,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
if (!result.isSuccessful()) {
throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND);
}
- actionType = result.isCreated() ? ActionType.ADDED : ActionType.UPDATED;
- if (result.isModified()) {
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), actionType, user);
- }
AlarmInfo resultAlarm = result.getAlarm();
if (alarm.isAcknowledged() && !resultAlarm.isAcknowledged()) {
resultAlarm = ack(resultAlarm, alarm.getAckTs(), user);
@@ -85,6 +81,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} else if (newAssignee == null && curAssignee != null) {
resultAlarm = unassign(alarm, alarm.getAssignTs(), user);
}
+ if (result.isModified()) {
+ notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), resultAlarm,
+ resultAlarm.getCustomerId(), actionType, user);
+ }
return new Alarm(resultAlarm);
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM), alarm, actionType, user, e);
@@ -103,6 +103,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
if (!result.isSuccessful()) {
throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND);
}
+ AlarmInfo alarmInfo = result.getAlarm();
if (result.isModified()) {
AlarmComment alarmComment = AlarmComment.builder()
.alarmId(alarm.getId())
@@ -117,11 +118,12 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_ACK, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_ACK, user);
} else {
throw new ThingsboardException("Alarm was already acknowledged!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
- return result.getAlarm();
+ return alarmInfo;
}
@Override
@@ -135,6 +137,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
if (!result.isSuccessful()) {
throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND);
}
+ AlarmInfo alarmInfo = result.getAlarm();
if (result.isCleared()) {
AlarmComment alarmComment = AlarmComment.builder()
.alarmId(alarm.getId())
@@ -149,11 +152,12 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_CLEAR, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_CLEAR, user);
} else {
throw new ThingsboardException("Alarm was already cleared!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
- return result.getAlarm();
+ return alarmInfo;
}
@Override
@@ -180,7 +184,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_ASSIGNED, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_ASSIGNED, user);
} else {
throw new ThingsboardException("Alarm was already assigned to this user!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
@@ -208,7 +213,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_UNASSIGNED, user);
} else {
throw new ThingsboardException("Alarm was already unassigned!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
@@ -239,7 +245,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} catch (ThingsboardException e) {
log.error("Failed to save alarm comment", e);
}
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(),
+ alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, user);
}
}
@@ -251,9 +258,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
@Override
public Boolean delete(Alarm alarm, User user) {
TenantId tenantId = alarm.getTenantId();
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, alarm.getOriginator());
- notificationEntityService.notifyDeleteAlarm(tenantId, alarm, alarm.getOriginator(), alarm.getCustomerId(),
- relatedEdgeIds, user, JacksonUtil.toString(alarm));
+ notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), alarm, alarm.getCustomerId(),
+ ActionType.DELETED, user);
return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId());
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
index ab57ecd050..6510ecfb7f 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
@@ -36,8 +36,6 @@ import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.profile.TbAssetProfileCache;
-import java.util.List;
-
import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE;
@Service
@@ -62,8 +60,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
}
Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
autoCommit(user, savedAsset.getId());
- notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), savedAsset,
- asset.getCustomerId(), actionType, user);
+ notificationEntityService.logEntityAction(tenantId, savedAsset.getId(), savedAsset, asset.getCustomerId(),
+ actionType, user);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedAsset.getId(),
asset.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
return savedAsset;
@@ -75,17 +73,16 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
@Override
public ListenableFuture delete(Asset asset, User user) {
+ ActionType actionType = ActionType.DELETED;
TenantId tenantId = asset.getTenantId();
AssetId assetId = asset.getId();
try {
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, assetId);
assetService.deleteAsset(tenantId, assetId);
- notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(),
- ActionType.DELETED, relatedEdgeIds, user, assetId.toString());
+ notificationEntityService.logEntityAction(tenantId, assetId, asset, asset.getCustomerId(), actionType, user, assetId.toString());
tbClusterService.broadcastEntityStateChangeEvent(tenantId, assetId, ComponentLifecycleEvent.DELETED);
return removeAlarmsByEntityId(tenantId, assetId);
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), ActionType.DELETED, user, e,
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e,
assetId.toString());
throw e;
}
@@ -97,8 +94,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
CustomerId customerId = customer.getId();
try {
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
- actionType, user, assetId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, customerId, actionType, user,
+ assetId.toString(), customerId.toString(), customer.getName());
return savedAsset;
} catch (Exception e) {
@@ -114,8 +111,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
try {
Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId));
CustomerId customerId = customer.getId();
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
- actionType, user, assetId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, customerId, actionType, user,
+ assetId.toString(), customerId.toString(), customer.getName());
return savedAsset;
} catch (Exception e) {
@@ -130,8 +127,9 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId()));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset,
- actionType, user, assetId.toString(), publicCustomer.getId().toString(), publicCustomer.getName());
+ CustomerId customerId = publicCustomer.getId();
+ notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, customerId, actionType, user,
+ assetId.toString(), customerId.toString(), publicCustomer.getName());
return savedAsset;
} catch (Exception e) {
@@ -146,9 +144,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
EdgeId edgeId = edge.getId();
try {
Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(tenantId, assetId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, savedAsset.getCustomerId(),
- edgeId, savedAsset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName());
-
+ notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, savedAsset.getCustomerId(),
+ actionType, user, assetId.toString(), edgeId.toString(), edge.getName());
return savedAsset;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType,
@@ -164,9 +161,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
EdgeId edgeId = edge.getId();
try {
Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(tenantId, assetId, edgeId));
-
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(),
- edgeId, asset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName());
+ notificationEntityService.logEntityAction(tenantId, assetId, asset, asset.getCustomerId(),
+ actionType, user, assetId.toString(), edgeId.toString(), edge.getName());
return savedAsset;
} catch (Exception e) {
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java
index b662994451..00b181a52a 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java
@@ -59,8 +59,8 @@ public class DefaultTbAssetProfileService extends AbstractTbEntityService implem
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedAssetProfile.getId(),
actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedAssetProfile.getId(),
- savedAssetProfile, user, actionType, true, null);
+ notificationEntityService.logEntityAction(tenantId, savedAssetProfile.getId(), savedAssetProfile,
+ null, actionType, user);
return savedAssetProfile;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), assetProfile, actionType, user, e);
@@ -70,16 +70,17 @@ public class DefaultTbAssetProfileService extends AbstractTbEntityService implem
@Override
public void delete(AssetProfile assetProfile, User user) {
+ ActionType actionType = ActionType.DELETED;
AssetProfileId assetProfileId = assetProfile.getId();
TenantId tenantId = assetProfile.getTenantId();
try {
assetProfileService.deleteAssetProfile(tenantId, assetProfileId);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, assetProfileId, ComponentLifecycleEvent.DELETED);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, assetProfileId, assetProfile,
- user, ActionType.DELETED, true, null, assetProfileId.toString());
+ notificationEntityService.logEntityAction(tenantId, assetProfileId, assetProfile, null,
+ actionType, user, assetProfileId.toString());
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), ActionType.DELETED,
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), actionType,
user, e, assetProfileId.toString());
throw e;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java
index b71cfd222e..96611bb3b5 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java
@@ -22,13 +22,10 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.CustomerId;
-import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
-import java.util.List;
-
@Service
@AllArgsConstructor
public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService {
@@ -40,7 +37,7 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements
try {
Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer));
autoCommit(user, savedCustomer.getId());
- notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, null, actionType, user);
+ notificationEntityService.logEntityAction(tenantId, savedCustomer.getId(), savedCustomer, null, actionType, user);
return savedCustomer;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), customer, actionType, user, e);
@@ -50,17 +47,17 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements
@Override
public void delete(Customer customer, User user) {
+ ActionType actionType = ActionType.DELETED;
TenantId tenantId = customer.getTenantId();
CustomerId customerId = customer.getId();
try {
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, customer.getId());
customerService.deleteCustomer(tenantId, customerId);
- notificationEntityService.notifyDeleteEntity(tenantId, customer.getId(), customer, customerId,
- ActionType.DELETED, relatedEdgeIds, user, customerId.toString());
+ notificationEntityService.logEntityAction(tenantId, customer.getId(), customer, customerId, actionType,
+ user, customerId.toString());
tbClusterService.broadcastEntityStateChangeEvent(tenantId, customer.getId(), ComponentLifecycleEvent.DELETED);
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), ActionType.DELETED,
- user, e, customerId.toString());
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), actionType, user,
+ e, customerId.toString());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
index fa5b967bd0..70918486a3 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
@@ -34,7 +34,6 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
@Service
@@ -51,8 +50,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
try {
Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard));
autoCommit(user, savedDashboard.getId());
- notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedDashboard.getId(), savedDashboard,
- null, actionType, user);
+ notificationEntityService.logEntityAction(tenantId, savedDashboard.getId(), savedDashboard, null,
+ actionType, user);
return savedDashboard;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), dashboard, actionType, user, e);
@@ -62,15 +61,14 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
@Override
public void delete(Dashboard dashboard, User user) {
+ ActionType actionType = ActionType.DELETED;
DashboardId dashboardId = dashboard.getId();
TenantId tenantId = dashboard.getTenantId();
try {
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, dashboardId);
dashboardService.deleteDashboard(tenantId, dashboardId);
- notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null,
- ActionType.DELETED, relatedEdgeIds, user, dashboardId.toString());
+ notificationEntityService.logEntityAction(tenantId, dashboardId, dashboard, null, actionType, user, dashboardId.toString());
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), ActionType.DELETED, user, e, dashboardId.toString());
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}
@@ -83,8 +81,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
DashboardId dashboardId = dashboard.getId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
- actionType, user, dashboardId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customerId, actionType,
+ user, dashboardId.toString(), customerId.toString(), customer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType,
@@ -101,9 +99,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, publicCustomer.getId()));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), savedDashboard,
- actionType, user, dashboardId.toString(),
- publicCustomer.getId().toString(), publicCustomer.getName());
+ notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, publicCustomer.getId(),
+ actionType, user, dashboardId.toString(), publicCustomer.getId().toString(), publicCustomer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
@@ -119,9 +116,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, publicCustomer.getId()));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), dashboard,
- actionType, user, dashboardId.toString(),
- publicCustomer.getId().toString(), publicCustomer.getName());
+ notificationEntityService.logEntityAction(tenantId, dashboardId, dashboard, publicCustomer.getId(), actionType,
+ user, dashboardId.toString(), publicCustomer.getId().toString(), publicCustomer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
@@ -159,15 +155,15 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard,
+ notificationEntityService.logEntityAction(tenantId, savedDashboard.getId(), savedDashboard, customerId,
actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard,
- ActionType.UNASSIGNED_FROM_CUSTOMER, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
+ notificationEntityService.logEntityAction(tenantId, savedDashboard.getId(), savedDashboard, customerId,
+ actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
return savedDashboard;
}
@@ -196,7 +192,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
+ notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customerId,
actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
return savedDashboard;
@@ -226,7 +222,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
+ notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customerId,
actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
return savedDashboard;
@@ -243,9 +239,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
EdgeId edgeId = edge.getId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(tenantId, dashboardId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, null,
- edgeId, savedDashboard, actionType, user, dashboardId.toString(),
- edgeId.toString(), edge.getName());
+ notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, null, actionType,
+ user, dashboardId.toString(), edgeId.toString(), edge.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
@@ -262,10 +257,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
EdgeId edgeId = edge.getId();
try {
Dashboard savedDevice = checkNotNull(dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edgeId));
-
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, null,
- edgeId, dashboard, actionType, user, dashboardId.toString(),
- edgeId.toString(), edge.getName());
+ notificationEntityService.logEntityAction(tenantId, dashboardId, dashboard, null, actionType,
+ user, dashboardId.toString(), edgeId.toString(), edge.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e,
@@ -281,7 +274,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
DashboardId dashboardId = dashboard.getId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customer.getId()));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customer.getId(), savedDashboard,
+ notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customer.getId(),
actionType, user, dashboardId.toString(), customer.getId().toString(), customer.getName());
return savedDashboard;
} catch (Exception e) {
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
index 2ab8de9438..544a199498 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
@@ -44,8 +44,6 @@ import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
-import java.util.List;
-
@AllArgsConstructor
@TbCoreComponent
@Service
@@ -97,10 +95,9 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
try {
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, deviceId);
deviceService.deleteDevice(tenantId, deviceId);
notificationEntityService.notifyDeleteDevice(tenantId, deviceId, device.getCustomerId(), device,
- relatedEdgeIds, user, deviceId.toString());
+ user, deviceId.toString());
return removeAlarmsByEntityId(tenantId, deviceId);
} catch (Exception e) {
@@ -116,8 +113,8 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
CustomerId customerId = customer.getId();
try {
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
- actionType, user, deviceId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, customerId, actionType, user,
+ deviceId.toString(), customerId.toString(), customer.getName());
return savedDevice;
} catch (Exception e) {
@@ -136,8 +133,8 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(tenantId, deviceId));
CustomerId customerId = customer.getId();
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
- actionType, user, deviceId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, customerId, actionType, user,
+ deviceId.toString(), customerId.toString(), customer.getName());
return savedDevice;
} catch (Exception e) {
@@ -154,9 +151,8 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
try {
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId()));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice,
- actionType, user, deviceId.toString(),
- publicCustomer.getId().toString(), publicCustomer.getName());
+ notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, savedDevice.getCustomerId(),
+ actionType, user, deviceId.toString(), publicCustomer.getId().toString(), publicCustomer.getName());
return savedDevice;
} catch (Exception e) {
@@ -252,30 +248,32 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
EdgeId edgeId = edge.getId();
try {
Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(tenantId, deviceId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, savedDevice.getCustomerId(),
- edgeId, savedDevice, actionType, user, deviceId.toString(), edgeId.toString(), edge.getName());
+ notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, savedDevice.getCustomerId(),
+ actionType, user, deviceId.toString(), edgeId.toString(), edge.getName());
+
return savedDevice;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
- ActionType.ASSIGNED_TO_EDGE, user, e, deviceId.toString(), edgeId.toString());
+ actionType, user, e, deviceId.toString(), edgeId.toString());
throw e;
}
}
@Override
public Device unassignDeviceFromEdge(Device device, Edge edge, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
EdgeId edgeId = edge.getId();
try {
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId));
+ notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, savedDevice.getCustomerId(),
+ actionType, user, deviceId.toString(), edgeId.toString(), edge.getName());
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, device.getCustomerId(),
- edgeId, device, ActionType.UNASSIGNED_FROM_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
- ActionType.UNASSIGNED_FROM_EDGE, user, e, deviceId.toString(), edgeId.toString());
+ actionType, user, e, deviceId.toString(), edgeId.toString());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java
index faa6a69983..70ee722493 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java
@@ -67,8 +67,8 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple
otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedDeviceProfile.getId(),
- savedDeviceProfile, user, actionType, true, null);
+ notificationEntityService.logEntityAction(tenantId, savedDeviceProfile.getId(), savedDeviceProfile,
+ null, actionType, user);
return savedDeviceProfile;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), deviceProfile, actionType, user, e);
@@ -78,6 +78,7 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple
@Override
public void delete(DeviceProfile deviceProfile, User user) {
+ ActionType actionType = ActionType.DELETED;
DeviceProfileId deviceProfileId = deviceProfile.getId();
TenantId tenantId = deviceProfile.getTenantId();
try {
@@ -85,10 +86,10 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple
tbClusterService.onDeviceProfileDelete(deviceProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, deviceProfileId, ComponentLifecycleEvent.DELETED);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, deviceProfileId, deviceProfile,
- user, ActionType.DELETED, true, null, deviceProfileId.toString());
+ notificationEntityService.logEntityAction(tenantId, deviceProfileId, deviceProfile, null,
+ actionType, user, deviceProfileId.toString());
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), ActionType.DELETED,
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), actionType,
user, e, deviceProfileId.toString());
throw e;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
index c51ae3352e..adc20c21d0 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
@@ -89,8 +89,8 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE
CustomerId customerId = customer.getId();
try {
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, edgeId, customerId, savedEdge,
- actionType, user, edgeId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, edgeId, savedEdge, customerId, actionType,
+ user, edgeId.toString(), customerId.toString(), customer.getName());
return savedEdge;
} catch (Exception e) {
@@ -108,8 +108,8 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE
CustomerId customerId = customer.getId();
try {
Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(tenantId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, edgeId, customerId, savedEdge,
- actionType, user, edgeId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, edgeId, savedEdge, customerId, actionType,
+ user, edgeId.toString(), customerId.toString(), customer.getName());
return savedEdge;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java
index b978b730fd..904d98653e 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java
@@ -40,41 +40,38 @@ public class DefaultTbEntityRelationService extends AbstractTbEntityService impl
@Override
public void save(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.RELATION_ADD_OR_UPDATE;
try {
relationService.saveRelation(tenantId, relation);
- notificationEntityService.notifyRelation(tenantId, customerId,
- relation, user, ActionType.RELATION_ADD_OR_UPDATE, relation);
+ notificationEntityService.logEntityRelationAction(tenantId, customerId,
+ relation, user, actionType, null, relation);
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId,
- ActionType.RELATION_ADD_OR_UPDATE, user, e, relation);
- notificationEntityService.logEntityAction(tenantId, relation.getTo(), null, customerId,
- ActionType.RELATION_ADD_OR_UPDATE, user, e, relation);
+ notificationEntityService.logEntityRelationAction(tenantId, customerId,
+ relation, user, actionType, e, relation);
throw e;
}
}
@Override
public void delete(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.RELATION_DELETED;
try {
boolean found = relationService.deleteRelation(tenantId, relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
if (!found) {
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
}
- notificationEntityService.notifyRelation(tenantId, customerId,
- relation, user, ActionType.RELATION_DELETED, relation);
+ notificationEntityService.logEntityRelationAction(tenantId, customerId, relation, user, actionType, null, relation);
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId,
- ActionType.RELATION_DELETED, user, e, relation);
- notificationEntityService.logEntityAction(tenantId, relation.getTo(), null, customerId,
- ActionType.RELATION_DELETED, user, e, relation);
+ notificationEntityService.logEntityRelationAction(tenantId, customerId,
+ relation, user, actionType, e, relation);
throw e;
}
}
@Override
- public void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException {
+ public void deleteCommonRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException {
try {
- relationService.deleteEntityRelations(tenantId, entityId);
+ relationService.deleteEntityCommonRelations(tenantId, entityId);
notificationEntityService.logEntityAction(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user);
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, entityId, null, customerId,
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java
index 2caee86d0c..8bf5018c95 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java
@@ -28,6 +28,6 @@ public interface TbEntityRelationService {
void delete(TenantId tenantId, CustomerId customerId, EntityRelation entity, User user) throws ThingsboardException;
- void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException;
+ void deleteCommonRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java
index 48e6c4b634..f587e19ef2 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java
@@ -81,7 +81,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
this.updateEntityViewAttributes(tenantId, savedEntityView, existingEntityView, user);
autoCommit(user, savedEntityView.getId());
- notificationEntityService.notifyCreateOrUpdateEntity(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView,
+ notificationEntityService.logEntityAction(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView,
null, actionType, user);
localCache.computeIfAbsent(savedEntityView.getTenantId(), (k) -> new ConcurrentReferenceHashMap<>()).clear();
tbClusterService.broadcastEntityStateChangeEvent(savedEntityView.getTenantId(), savedEntityView.getId(),
@@ -129,10 +129,9 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
TenantId tenantId = entityView.getTenantId();
EntityViewId entityViewId = entityView.getId();
try {
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, entityViewId);
entityViewService.deleteEntityView(tenantId, entityViewId);
- notificationEntityService.notifyDeleteEntity(tenantId, entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED,
- relatedEdgeIds, user, entityViewId.toString());
+ notificationEntityService.logEntityAction(tenantId, entityViewId, entityView, entityView.getCustomerId(),
+ ActionType.DELETED, user, entityViewId.toString());
localCache.computeIfAbsent(tenantId, (k) -> new ConcurrentReferenceHashMap<>()).clear();
tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityViewId, ComponentLifecycleEvent.DELETED);
@@ -145,15 +144,31 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
@Override
public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId();
try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, entityViewId, customerId));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customerId, savedEntityView,
- ActionType.ASSIGNED_TO_CUSTOMER, user, entityViewId.toString(), customerId.toString(), customer.getName());
+ notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, savedEntityView.getCustomerId(),
+ actionType, user, entityViewId.toString(), customerId.toString(), customer.getName());
+ return savedEntityView;
+ } catch (Exception e) {
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
+ actionType, user, e, entityViewId.toString(), customerId.toString());
+ throw e;
+ }
+ }
+
+ @Override
+ public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
+ try {
+ EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId));
+ notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, customer.getId(),
+ actionType, user, savedEntityView.getId().toString(), customer.getId().toString(), customer.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
- ActionType.ASSIGNED_TO_CUSTOMER, user, e, entityViewId.toString(), customerId.toString());
+ actionType, user, e, entityViewId.toString());
throw e;
}
}
@@ -165,9 +180,8 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId,
entityViewId, publicCustomer.getId()));
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, savedEntityView.getCustomerId(), savedEntityView,
- actionType, user, savedEntityView.getId().toString(),
- publicCustomer.getId().toString(), publicCustomer.getName());
+ notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, savedEntityView.getCustomerId(),
+ actionType, user, savedEntityView.getId().toString(), publicCustomer.getId().toString(), publicCustomer.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
@@ -178,16 +192,16 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
@Override
public EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
EdgeId edgeId = edge.getId();
try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId,
- edgeId, savedEntityView, ActionType.ASSIGNED_TO_EDGE, user, savedEntityView.getEntityId().toString(),
- edgeId.toString(), edge.getName());
+ notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, customerId, actionType,
+ user, savedEntityView.getEntityId().toString(), edgeId.toString(), edge.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
- ActionType.ASSIGNED_TO_EDGE, user, e, entityViewId.toString(), edgeId.toString());
+ actionType, user, e, entityViewId.toString(), edgeId.toString());
throw e;
}
}
@@ -195,34 +209,17 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
@Override
public EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView,
Edge edge, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
EntityViewId entityViewId = entityView.getId();
EdgeId edgeId = edge.getId();
try {
EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(tenantId, entityViewId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId,
- edgeId, entityView, ActionType.UNASSIGNED_FROM_EDGE, user, entityViewId.toString(),
- edgeId.toString(), edge.getName());
+ notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, customerId, actionType,
+ user, entityViewId.toString(), edgeId.toString(), edge.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
- ActionType.UNASSIGNED_FROM_EDGE, user, e, entityViewId.toString(), edgeId.toString());
- throw e;
- }
- }
-
- @Override
- public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
- ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
- try {
- EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId));
-
- notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customer.getId(), savedEntityView,
- actionType, user, savedEntityView.getId().toString(), customer.getId().toString(), customer.getName());
-
- return savedEntityView;
- } catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
- actionType, user, e, entityViewId.toString());
+ actionType, user, e, entityViewId.toString(), edgeId.toString());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java
index 4d3c61e615..3cc444caf5 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java
@@ -50,9 +50,8 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
try {
OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(new OtaPackageInfo(saveOtaPackageInfoRequest), saveOtaPackageInfoRequest.isUsesUrl());
- boolean sendMsgToEdge = savedOtaPackageInfo.hasUrl() || savedOtaPackageInfo.isHasData();
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackageInfo.getId(),
- savedOtaPackageInfo, user, actionType, sendMsgToEdge, null);
+ notificationEntityService.logEntityAction(tenantId, savedOtaPackageInfo.getId(), savedOtaPackageInfo,
+ null, actionType, user);
return savedOtaPackageInfo;
} catch (Exception e) {
@@ -65,6 +64,7 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
@Override
public OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm,
byte[] data, String filename, String contentType, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.UPDATED;
TenantId tenantId = otaPackageInfo.getTenantId();
OtaPackageId otaPackageId = otaPackageInfo.getId();
try {
@@ -87,27 +87,26 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
otaPackage.setData(ByteBuffer.wrap(data));
otaPackage.setDataSize((long) data.length);
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackage.getId(),
- savedOtaPackage, user, ActionType.UPDATED, true, null);
+ notificationEntityService.logEntityAction(tenantId, savedOtaPackage.getId(), savedOtaPackage, null, actionType, user);
return savedOtaPackage;
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), ActionType.UPDATED,
- user, e, otaPackageId.toString());
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), actionType, user, e, otaPackageId.toString());
throw e;
}
}
@Override
public void delete(OtaPackageInfo otaPackageInfo, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.DELETED;
TenantId tenantId = otaPackageInfo.getTenantId();
OtaPackageId otaPackageId = otaPackageInfo.getId();
try {
otaPackageService.deleteOtaPackage(tenantId, otaPackageId);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, otaPackageId, otaPackageInfo,
- user, ActionType.DELETED, true, null, otaPackageInfo.getId().toString());
+ notificationEntityService.logEntityAction(tenantId, otaPackageId, otaPackageInfo, null,
+ actionType, user, otaPackageInfo.getId().toString());
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE),
- ActionType.DELETED, user, e, otaPackageId.toString());
+ actionType, user, e, otaPackageId.toString());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
index 63e11aeb7a..40d294d238 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
@@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.TenantProfile;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.Queue;
@@ -71,8 +70,6 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
onQueueUpdated(savedQueue, oldQueue);
}
- notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), savedQueue.getId(), create ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
-
return savedQueue;
}
@@ -145,8 +142,6 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
}
}
}, DELETE_DELAY, TimeUnit.SECONDS);
-
- notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), queue.getId(), EdgeEventActionType.DELETED);
}
@Override
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 0c04e46ff5..58bd40d070 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
@@ -54,7 +54,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
ActionType actionType = tbUser.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
try {
boolean sendEmail = tbUser.getId() == null && sendActivationMail;
- User savedUser = checkNotNull(userService.saveUser(tbUser));
+ User savedUser = checkNotNull(userService.saveUser(tenantId, tbUser));
if (sendEmail) {
UserCredentials userCredentials = userService.findUserCredentialsByUserId(tenantId, savedUser.getId());
String baseUrl = systemSecurityService.getBaseUrl(tenantId, customerId, request);
@@ -68,8 +68,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
throw e;
}
}
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, savedUser.getId(),
- savedUser, user, actionType, true, null);
+ notificationEntityService.logEntityAction(tenantId, savedUser.getId(), savedUser, customerId, actionType, user);
return savedUser;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), tbUser, actionType, user, e);
@@ -79,16 +78,16 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
@Override
public void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.DELETED;
UserId userId = tbUser.getId();
try {
- tbAlarmService.unassignUserAlarms(tenantId, tbUser, System.currentTimeMillis());
+ tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis());
userService.deleteUser(tenantId, userId);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser,
- user, ActionType.DELETED, true, null, customerId.toString());
+ notificationEntityService.logEntityAction(tenantId, userId, tbUser, customerId, actionType, user, customerId.toString());
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER),
- ActionType.DELETED, user, e, userId.toString());
+ actionType, user, e, userId.toString());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java
index 7cc150b746..efc20cd422 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java
@@ -40,8 +40,8 @@ public class DefaultWidgetsBundleService extends AbstractTbEntityService impleme
try {
WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
autoCommit(user, savedWidgetsBundle.getId());
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedWidgetsBundle.getId(),
- savedWidgetsBundle, user, actionType, true, null);
+ notificationEntityService.logEntityAction(tenantId, savedWidgetsBundle.getId(), savedWidgetsBundle,
+ null, actionType, user);
return savedWidgetsBundle;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE), widgetsBundle, actionType, user, e);
@@ -51,14 +51,13 @@ public class DefaultWidgetsBundleService extends AbstractTbEntityService impleme
@Override
public void delete(WidgetsBundle widgetsBundle, User user) {
+ ActionType actionType = ActionType.DELETED;
TenantId tenantId = widgetsBundle.getTenantId();
try {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId());
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, widgetsBundle.getId(), widgetsBundle,
- user, ActionType.DELETED, true, null);
+ notificationEntityService.logEntityAction(tenantId, widgetsBundle.getId(), widgetsBundle, null, actionType, user);
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE),
- ActionType.DELETED, user, e, widgetsBundle.getId());
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE), actionType, user, e, widgetsBundle.getId());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
index 7965824274..acadd35577 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
@@ -114,13 +114,14 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
+
@Service
@Profile("install")
@Slf4j
public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public static final String CUSTOMER_CRED = "customer";
- public static final String DEFAULT_DEVICE_TYPE = "default";
public static final String ACTIVITY_STATE = "active";
@Autowired
@@ -524,7 +525,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
user.setEmail(email);
user.setTenantId(tenantId);
user.setCustomerId(customerId);
- user = userService.saveUser(user);
+ user = userService.saveUser(tenantId, user);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId());
userCredentials.setPassword(passwordEncoder.encode(password));
userCredentials.setEnabled(true);
diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
index dafccfdad6..ff53682ca7 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
@@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry;
+import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.page.PageLink;
@@ -502,7 +503,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
md.getNodes().add(ruleNode);
md.setFirstNodeIndex(newIdx);
- md.addConnectionInfo(newIdx, oldIdx, "Success");
+ md.addConnectionInfo(newIdx, oldIdx, TbNodeConnectionType.SUCCESS);
ruleChainService.saveRuleChainMetaData(tenant.getId(), md, Function.identity());
}
} catch (Exception e) {
diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
index 1c6af41360..246fa4a0fa 100644
--- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
+++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
@@ -16,7 +16,6 @@
package org.thingsboard.server.service.mail;
import com.fasterxml.jackson.databind.JsonNode;
-
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
index 76631aaa95..53ef38d96a 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
@@ -32,10 +32,10 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
+import org.thingsboard.server.common.data.HasRuleEngineProfile;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
-import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AssetId;
@@ -178,15 +178,8 @@ public class DefaultTbClusterService implements TbClusterService {
return;
}
} else {
- if (entityId.getEntityType().equals(EntityType.DEVICE)) {
- tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())));
- } else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) {
- tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId())));
- } else if (entityId.getEntityType().equals(EntityType.ASSET)) {
- tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetId(entityId.getId())));
- } else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) {
- tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId())));
- }
+ HasRuleEngineProfile ruleEngineProfile = getRuleEngineProfileForEntityOrElseNull(tenantId, entityId);
+ tbMsg = transformMsg(tbMsg, ruleEngineProfile);
}
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId);
log.trace("PUSHING msg: {} to:{}", tbMsg, tpi);
@@ -198,34 +191,33 @@ public class DefaultTbClusterService implements TbClusterService {
toRuleEngineMsgs.incrementAndGet();
}
- private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) {
- if (deviceProfile != null) {
- RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId();
- String targetQueueName = deviceProfile.getDefaultQueueName();
- tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName);
+ private HasRuleEngineProfile getRuleEngineProfileForEntityOrElseNull(TenantId tenantId, EntityId entityId) {
+ if (entityId.getEntityType().equals(EntityType.DEVICE)) {
+ return deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
+ } else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) {
+ return deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId()));
+ } else if (entityId.getEntityType().equals(EntityType.ASSET)) {
+ return assetProfileCache.get(tenantId, new AssetId(entityId.getId()));
+ } else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) {
+ return assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId()));
}
- return tbMsg;
- }
-
- private TbMsg transformMsg(TbMsg tbMsg, AssetProfile assetProfile) {
- if (assetProfile != null) {
- RuleChainId targetRuleChainId = assetProfile.getDefaultRuleChainId();
- String targetQueueName = assetProfile.getDefaultQueueName();
- tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName);
- }
- return tbMsg;
- }
-
- private TbMsg transformMsg(TbMsg tbMsg, RuleChainId targetRuleChainId, String targetQueueName) {
- boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
- boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
-
- if (isRuleChainTransform && isQueueTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
- } else if (isRuleChainTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId);
- } else if (isQueueTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName);
+ return null;
+ }
+ private TbMsg transformMsg(TbMsg tbMsg, HasRuleEngineProfile ruleEngineProfile) {
+ if (ruleEngineProfile != null) {
+ RuleChainId targetRuleChainId = ruleEngineProfile.getDefaultRuleChainId();
+ String targetQueueName = ruleEngineProfile.getDefaultQueueName();
+
+ boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
+ boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
+
+ if (isRuleChainTransform && isQueueTransform) {
+ tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
+ } else if (isRuleChainTransform) {
+ tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId);
+ } else if (isQueueTransform) {
+ tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName);
+ }
}
return tbMsg;
}
@@ -466,11 +458,6 @@ public class DefaultTbClusterService implements TbClusterService {
@Override
public void onDeviceUpdated(Device device, Device old) {
- onDeviceUpdated(device, old, true);
- }
-
- @Override
- public void onDeviceUpdated(Device device, Device old, boolean notifyEdge) {
var created = old == null;
broadcastEntityChangeToTransport(device.getTenantId(), device.getId(), device, null);
if (old != null) {
@@ -485,9 +472,6 @@ public class DefaultTbClusterService implements TbClusterService {
broadcastEntityStateChangeEvent(device.getTenantId(), device.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
sendDeviceStateServiceEvent(device.getTenantId(), device.getId(), created, !created, false);
otaPackageStateService.update(device, old);
- if (!created && notifyEdge) {
- sendNotificationMsgToEdge(device.getTenantId(), null, device.getId(), null, null, EdgeEventActionType.UPDATED);
- }
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
index dc24d6df33..fef22acf40 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
@@ -32,10 +32,11 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
-import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger;
+import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
@@ -63,7 +64,6 @@ import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
-import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
index 51f4d5283f..ac7d796e33 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
@@ -363,7 +363,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
callback.onSuccess();
}
} catch (Exception e) {
- callback.onFailure(new RuleEngineException(e.getMessage()));
+ callback.onFailure(new RuleEngineException(e.getMessage(), e));
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java b/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java
index ef2ba8798d..c2171c2550 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/TbMsgPackCallback.java
@@ -17,11 +17,14 @@ package org.thingsboard.server.service.queue;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.common.util.ExceptionUtil;
+import org.thingsboard.server.common.data.exception.AbstractRateLimitException;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.common.msg.queue.RuleNodeInfo;
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
+import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -57,8 +60,23 @@ public class TbMsgPackCallback implements TbMsgCallback {
ctx.onSuccess(id);
}
+ @Override
+ public void onRateLimit(RuleEngineException e) {
+ log.debug("[{}] ON RATE LIMIT", id, e);
+ //TODO notify tenant on rate limit
+ if (failedMsgTimer != null) {
+ failedMsgTimer.record(System.currentTimeMillis() - startMsgProcessing, TimeUnit.MILLISECONDS);
+ }
+ ctx.onSuccess(id);
+ }
+
@Override
public void onFailure(RuleEngineException e) {
+ if (ExceptionUtil.lookupExceptionInCause(e, AbstractRateLimitException.class) != null) {
+ onRateLimit(e);
+ return;
+ }
+
log.trace("[{}] ON FAILURE", id, e);
if (failedMsgTimer != null) {
failedMsgTimer.record(System.currentTimeMillis() - startMsgProcessing, TimeUnit.MILLISECONDS);
diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java
index bca7c7d81a..8ea7208c55 100644
--- a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java
+++ b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java
@@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.rpc;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -27,6 +26,7 @@ import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
@@ -182,7 +182,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
entityNode.put(DataConstants.ADDITIONAL_INFO, msg.getAdditionalInfo());
try {
- TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java
index ad40176cef..8c6f0d768c 100644
--- a/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java
+++ b/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java
@@ -24,6 +24,7 @@ import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RpcId;
import org.thingsboard.server.common.data.id.TenantId;
+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.rpc.Rpc;
@@ -62,7 +63,7 @@ public class TbRpcService {
}
private void pushRpcMsgToRuleEngine(TenantId tenantId, Rpc rpc) {
- TbMsg msg = TbMsg.newMsg("RPC_" + rpc.getStatus().name(), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
+ TbMsg msg = TbMsg.newMsg(TbMsgType.valueOf("RPC_" + rpc.getStatus().name()), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
tbClusterService.pushMsgToRuleEngine(tenantId, rpc.getDeviceId(), msg, null);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java
index 5756101ee1..884c614231 100644
--- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java
+++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java
@@ -29,7 +29,6 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId;
@@ -185,9 +184,7 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedRuleChain.getId(),
actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
}
- boolean sendMsgToEdge = RuleChainType.EDGE.equals(savedRuleChain.getType()) && actionType.equals(ActionType.UPDATED);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedRuleChain.getId(),
- savedRuleChain, user, actionType, sendMsgToEdge, null);
+ notificationEntityService.logEntityAction(tenantId, savedRuleChain.getId(), savedRuleChain, null, actionType, user);
return savedRuleChain;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN), ruleChain, actionType, user, e);
@@ -204,11 +201,6 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement
Set referencingRuleChainIds = referencingRuleNodes.stream().map(RuleNode::getRuleChainId).collect(Collectors.toSet());
- List relatedEdgeIds = null;
- if (RuleChainType.EDGE.equals(ruleChain.getType())) {
- relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, ruleChainId);
- }
-
ruleChainService.deleteRuleChainById(tenantId, ruleChainId);
referencingRuleChainIds.remove(ruleChain.getId());
@@ -220,7 +212,7 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement
tbClusterService.broadcastEntityStateChangeEvent(tenantId, ruleChain.getId(), ComponentLifecycleEvent.DELETED);
}
- notificationEntityService.notifyDeleteRuleChain(tenantId, ruleChain, relatedEdgeIds, user);
+ notificationEntityService.logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, ruleChainId.toString());
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN), ActionType.DELETED,
user, e, ruleChainId.toString());
@@ -310,14 +302,8 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement
notificationEntityService.logEntityAction(tenantId, ruleChainId, ruleChain, ActionType.UPDATED, user, ruleChainMetaData);
- if (RuleChainType.EDGE.equals(ruleChain.getType())) {
- notificationEntityService.notifySendMsgToEdgeService(tenantId, ruleChain.getId(), EdgeEventActionType.UPDATED);
- }
-
for (RuleChain updatedRuleChain : updatedRuleChains) {
- if (RuleChainType.EDGE.equals(ruleChain.getType())) {
- notificationEntityService.notifySendMsgToEdgeService(tenantId, updatedRuleChain.getId(), EdgeEventActionType.UPDATED);
- } else {
+ if (RuleChainType.CORE.equals(ruleChain.getType())) {
RuleChainMetaData updatedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, updatedRuleChain.getId()));
notificationEntityService.logEntityAction(tenantId, updatedRuleChain.getId(), updatedRuleChain,
ActionType.UPDATED, user, updatedRuleChainMetaData);
@@ -333,34 +319,34 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement
@Override
public RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChain ruleChain, Edge edge, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
RuleChainId ruleChainId = ruleChain.getId();
EdgeId edgeId = edge.getId();
try {
RuleChain savedRuleChain = checkNotNull(ruleChainService.assignRuleChainToEdge(tenantId, ruleChainId, edgeId));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, ruleChainId,
- null, edgeId, savedRuleChain, ActionType.ASSIGNED_TO_EDGE,
+ notificationEntityService.logEntityAction(tenantId, ruleChainId, savedRuleChain, null, actionType,
user, ruleChainId.toString(), edgeId.toString(), edge.getName());
return savedRuleChain;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN),
- ActionType.ASSIGNED_TO_EDGE, user, e, ruleChainId.toString(), edgeId.toString());
+ actionType, user, e, ruleChainId.toString(), edgeId.toString());
throw e;
}
}
@Override
public RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChain ruleChain, Edge edge, User user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
RuleChainId ruleChainId = ruleChain.getId();
EdgeId edgeId = edge.getId();
try {
RuleChain savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(tenantId, ruleChainId, edgeId, false));
- notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, ruleChainId,
- null, edgeId, savedRuleChain, ActionType.UNASSIGNED_FROM_EDGE,
+ notificationEntityService.logEntityAction(tenantId, ruleChainId, savedRuleChain, null, actionType,
user, ruleChainId.toString(), edgeId.toString(), edge.getName());
return savedRuleChain;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN),
- ActionType.UNASSIGNED_FROM_EDGE, user, e, ruleChainId, edgeId);
+ actionType, user, e, ruleChainId, edgeId);
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
index 554359fd6d..8b09565ef9 100644
--- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
+++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
@@ -36,7 +36,6 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
-import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceIdInfo;
import org.thingsboard.server.common.data.EntityType;
@@ -51,6 +50,8 @@ import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.query.EntityData;
@@ -63,7 +64,6 @@ 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.common.msg.notification.NotificationRuleProcessor;
-import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@@ -102,10 +102,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
-import static org.thingsboard.server.common.data.DataConstants.ACTIVITY_EVENT;
-import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT;
-import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT;
-import static org.thingsboard.server.common.data.DataConstants.INACTIVITY_EVENT;
+import static org.thingsboard.server.common.data.DataConstants.SCOPE;
import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE;
/**
@@ -229,7 +226,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService> tsData = tsService.findLatest(TenantId.SYS_TENANT_ID, device.getId(), PERSISTENT_ATTRIBUTES);
future = Futures.transform(tsData, extractDeviceStateData(device), deviceStateExecutor);
} else {
- ListenableFuture> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), DataConstants.SERVER_SCOPE, PERSISTENT_ATTRIBUTES);
+ ListenableFuture> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), SERVER_SCOPE, PERSISTENT_ATTRIBUTES);
future = Futures.transform(attrData, extractDeviceStateData(device), deviceStateExecutor);
}
return transformInactivityTimeout(future);
@@ -771,11 +768,11 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value));
} else {
- tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
+ tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
}
}
@@ -811,7 +808,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value));
} else {
- tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
+ tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
index 3b37b0fe26..dcb6764201 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
@@ -25,15 +25,15 @@ 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.EntityId;
+import org.thingsboard.server.common.data.limit.LimitedApi;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.util.ThrowingRunnable;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.RelationService;
-import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.common.data.limit.LimitedApi;
import org.thingsboard.server.dao.util.limits.RateLimitService;
+import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService;
@@ -119,8 +119,8 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
relationService.saveRelations(ctx.getTenantId(), new ArrayList<>(ctx.getRelations()));
for (EntityRelation relation : ctx.getRelations()) {
- entityNotificationService.notifyRelation(ctx.getTenantId(), null,
- relation, ctx.getUser(), ActionType.RELATION_ADD_OR_UPDATE, relation);
+ entityNotificationService.logEntityRelationAction(ctx.getTenantId(), null,
+ relation, ctx.getUser(), ActionType.RELATION_ADD_OR_UPDATE, null, relation);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java
index 7f0af64ed7..3255c418c5 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java
@@ -58,8 +58,8 @@ public class AssetProfileImportService extends BaseEntityImportService {
- entityNotificationService.notifyRelation(tenantId, null,
- existingRelation, ctx.getUser(), ActionType.RELATION_DELETED, existingRelation);
+ entityNotificationService.logEntityRelationAction(tenantId, null,
+ existingRelation, ctx.getUser(), ActionType.RELATION_DELETED, null, existingRelation);
});
} else if (Objects.equal(relation.getAdditionalInfo(), existingRelation.getAdditionalInfo())) {
relationsMap.remove(relation);
@@ -266,8 +266,8 @@ public abstract class BaseEntityImportService taskCache;
@@ -432,12 +429,11 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
return exportableEntitiesService.findEntitiesByTenantId(ctx.getTenantId(), entityType, pageLink);
}, 100, entity -> {
if (ctx.getImportedEntities().get(entityType) == null || !ctx.getImportedEntities().get(entityType).contains(entity.getId())) {
- List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(ctx.getTenantId(), entity.getId());
exportableEntitiesService.removeById(ctx.getTenantId(), entity.getId());
ctx.addEventCallback(() -> {
- entityNotificationService.notifyDeleteEntity(ctx.getTenantId(), entity.getId(),
- entity, null, ActionType.DELETED, relatedEdgeIds, ctx.getUser());
+ entityNotificationService.logEntityAction(ctx.getTenantId(), entity.getId(), entity, null,
+ ActionType.DELETED, ctx.getUser());
});
ctx.registerDeleted(entityType);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
index 1603d33bfd..b2b9d992e6 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
@@ -44,15 +44,15 @@ import org.thingsboard.server.common.data.id.CustomerId;
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.notification.rule.trigger.AlarmTrigger;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
-import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger;
+import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.dao.alarm.AlarmService;
-import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService;
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java
index 3f5e52796a..df3a15e765 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java
@@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
@@ -78,6 +79,9 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
private ExecutorService tsCallBackExecutor;
+ @Value("${sql.ts.value_no_xss_validation:false}")
+ private boolean valueNoXssValidation;
+
public DefaultTelemetrySubscriptionService(AttributesService attrService,
TimeseriesService tsService,
@Lazy TbEntityViewService tbEntityViewService,
@@ -135,7 +139,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
checkInternalEntity(entityId);
boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null;
if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) {
- KvUtils.validate(ts);
+ KvUtils.validate(ts, valueNoXssValidation);
if (saveLatest) {
saveAndNotifyInternal(tenantId, entityId, ts, ttl, getCallback(tenantId, customerId, sysTenant, callback));
} else {
diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
index d0d996fe1f..89a7480708 100644
--- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
+++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
@@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.page.PageData;
@@ -346,7 +347,7 @@ public class DefaultTransportApiService implements TransportApiService {
DeviceId deviceId = device.getId();
JsonNode entityNode = JacksonUtil.valueToTree(device);
- TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null);
} else {
JsonNode deviceAdditionalInfo = device.getAdditionalInfo();
diff --git a/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java b/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java
index 4a07444bbb..0deb2f6bb7 100644
--- a/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java
+++ b/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java
@@ -16,8 +16,6 @@
package org.thingsboard.server.utils;
import lombok.extern.slf4j.Slf4j;
-import org.eclipse.leshan.core.model.DDFFileParser;
-import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.ObjectModel;
import org.thingsboard.server.common.data.ResourceType;
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index c8dfd1b029..e874e41cd7 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -96,6 +96,10 @@ zk:
session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}"
# Name of the directory in zookeeper 'filesystem'
zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}"
+ # The recalculate_delay property recommended in a microservices architecture setup for rule-engine services.
+ # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions.
+ # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability.
+ recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}"
cluster:
stats:
@@ -249,7 +253,8 @@ cassandra:
concurrent_limit: "${CASSANDRA_QUERY_CONCURRENT_LIMIT:1000}"
permit_max_wait_time: "${PERMIT_MAX_WAIT_TIME:120000}"
dispatcher_threads: "${CASSANDRA_QUERY_DISPATCHER_THREADS:2}"
- callback_threads: "${CASSANDRA_QUERY_CALLBACK_THREADS:4}"
+ callback_threads: "${CASSANDRA_QUERY_CALLBACK_THREADS:4}" # Buffered rate executor (read, write), for managing I/O rate. See "nosql-*-callback" threads in JMX
+ result_processing_threads: "${CASSANDRA_QUERY_RESULT_PROCESSING_THREADS:50}" # Result set transformer and processing. See "cassandra-callback" threads in JMX
poll_ms: "${CASSANDRA_QUERY_POLL_MS:50}"
rate_limit_print_interval_ms: "${CASSANDRA_QUERY_RATE_LIMIT_PRINT_MS:10000}"
# set all data types values except target to null for the same ts on save
@@ -267,11 +272,13 @@ sql:
batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}"
stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}"
batch_threads: "${SQL_ATTRIBUTES_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
+ value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}"
ts:
batch_size: "${SQL_TS_BATCH_SIZE:10000}"
batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}"
stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}"
batch_threads: "${SQL_TS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
+ value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}"
ts_latest:
batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}"
batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}"
@@ -985,6 +992,35 @@ transport:
enabled: "${TB_TRANSPORT_STATS_ENABLED:true}"
print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}"
+# Device connectivity properties to publish telemetry
+device:
+ connectivity:
+ http:
+ enabled: "${DEVICE_CONNECTIVITY_HTTP_ENABLED:true}"
+ host: "${DEVICE_CONNECTIVITY_HTTP_HOST:}"
+ port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}"
+ https:
+ enabled: "${DEVICE_CONNECTIVITY_HTTPS_ENABLED:false}"
+ host: "${DEVICE_CONNECTIVITY_HTTPS_HOST:}"
+ port: "${DEVICE_CONNECTIVITY_HTTPS_PORT:443}"
+ mqtt:
+ enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:true}"
+ host: "${DEVICE_CONNECTIVITY_MQTT_HOST:}"
+ port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}"
+ mqtts:
+ enabled: "${DEVICE_CONNECTIVITY_MQTTS_ENABLED:false}"
+ host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}"
+ port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}"
+ pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:mqttserver.pem}"
+ coap:
+ enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}"
+ host: "${DEVICE_CONNECTIVITY_COAP_HOST:}"
+ port: "${DEVICE_CONNECTIVITY_COAP_PORT:5683}"
+ coaps:
+ enabled: "${DEVICE_CONNECTIVITY_COAPS_ENABLED:false}"
+ host: "${DEVICE_CONNECTIVITY_COAPS_HOST:}"
+ port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}"
+
# Edges parameters
edges:
enabled: "${EDGES_ENABLED:true}"
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
index d5eabdff2a..71c244890d 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
@@ -74,6 +74,17 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.reset(tbClusterService, auditLogService);
}
+ protected void testNotifyAssignUnassignEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId,
+ TenantId tenantId, CustomerId customerId, UserId userId, String userName,
+ ActionType actionType, ActionType actionTypeEdge, Object... additionalInfo) {
+ int cntTime = 1;
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionTypeEdge, cntTime);
+ testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
+ ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
+ Mockito.reset(tbClusterService, auditLogService);
+ }
+
protected void testNotifyEntityAllOneTimeRelation(EntityRelation relation,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
@@ -115,9 +126,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
protected void testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(HasName entity, EntityId entityId, EntityId originatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
- ActionType actionType, Object... additionalInfo) {
+ ActionType actionType, ActionType actionTypeEdge, Object... additionalInfo) {
int cntTime = 1;
- testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionTypeEdge, cntTime);
testLogEntityActionEntityEqClass(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
@@ -163,10 +174,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(HasName entity, HasName originator,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
- ActionType actionType, ActionType actionTypeEdge,
+ ActionType actionType,
int cntTime, int cntTimeEdge, int cntTimeRuleEngine, Object... additionalInfo) {
EntityId originatorId = createEntityId_NULL_UUID(originator);
- testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionTypeEdge, cntTimeEdge);
+ testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionType, cntTimeEdge);
ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
ArgumentMatcher matcherCustomerId = customerId == null ?
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
index 49e3550a1e..656936b175 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
@@ -25,13 +25,13 @@ import org.thingsboard.server.common.data.event.EventType;
import org.thingsboard.server.common.data.id.EntityId;
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.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.rule.RuleChainService;
-import java.io.IOException;
import java.util.function.Predicate;
/**
@@ -82,8 +82,8 @@ public abstract class AbstractRuleEngineControllerTest extends AbstractControlle
}
}
- protected Predicate filterByCustomEvent() {
- return event -> event.getBody().get("msgType").textValue().equals("CUSTOM");
+ protected Predicate filterByPostTelemetryEventType() {
+ return event -> event.getBody().get("msgType").textValue().equals(TbMsgType.POST_TELEMETRY_REQUEST.name());
}
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
index 7f57fbbb3f..c32b4cf8d7 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
@@ -95,6 +95,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
@@ -188,7 +189,9 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
protected String username;
protected TenantId tenantId;
+ protected TenantProfileId tenantProfileId;
protected UserId tenantAdminUserId;
+ protected User tenantAdminUser;
protected CustomerId tenantAdminCustomerId;
protected CustomerId customerId;
protected TenantId differentTenantId;
@@ -269,15 +272,16 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantId = savedTenant.getId();
+ tenantProfileId = savedTenant.getTenantProfileId();
- User tenantAdmin = new User();
- tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
- tenantAdmin.setTenantId(tenantId);
- tenantAdmin.setEmail(TENANT_ADMIN_EMAIL);
+ tenantAdminUser = new User();
+ tenantAdminUser.setAuthority(Authority.TENANT_ADMIN);
+ tenantAdminUser.setTenantId(tenantId);
+ tenantAdminUser.setEmail(TENANT_ADMIN_EMAIL);
- tenantAdmin = createUserAndLogin(tenantAdmin, TENANT_ADMIN_PASSWORD);
- tenantAdminUserId = tenantAdmin.getId();
- tenantAdminCustomerId = tenantAdmin.getCustomerId();
+ tenantAdminUser = createUserAndLogin(tenantAdminUser, TENANT_ADMIN_PASSWORD);
+ tenantAdminUserId = tenantAdminUser.getId();
+ tenantAdminCustomerId = tenantAdminUser.getCustomerId();
Customer customer = new Customer();
customer.setTitle("Customer");
@@ -792,6 +796,10 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return readResponse(doDelete(urlTemplate, params).andExpect(status().isOk()), responseClass);
}
+ protected T doDeleteAsync(String urlTemplate, Class responseClass, String... params) throws Exception {
+ return readResponse(doDeleteAsync(urlTemplate, DEFAULT_TIMEOUT, params).andExpect(status().isOk()), responseClass);
+ }
+
protected ResultActions doPost(String urlTemplate, String... params) throws Exception {
MockHttpServletRequestBuilder postRequest = post(urlTemplate);
setJwtToken(postRequest);
@@ -824,6 +832,15 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return mockMvc.perform(deleteRequest);
}
+ protected ResultActions doDeleteAsync(String urlTemplate, Long timeout, String... params) throws Exception {
+ MockHttpServletRequestBuilder deleteRequest = delete(urlTemplate, params);
+ setJwtToken(deleteRequest);
+// populateParams(deleteRequest, params);
+ MvcResult result = mockMvc.perform(deleteRequest).andReturn();
+ result.getAsyncResult(timeout);
+ return mockMvc.perform(asyncDispatch(result));
+ }
+
protected void populateParams(MockHttpServletRequestBuilder request, String... params) {
if (params != null && params.length > 0) {
Assert.assertEquals(0, params.length % 2);
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 50761be096..36c5eacd36 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java
@@ -158,8 +158,10 @@ public class AlarmControllerTest extends AbstractControllerTest {
Assert.assertEquals(alarm.getAckTs(), updatedAlarm.getAckTs());
foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class);
- testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
- tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ACK);
+
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId,
+ customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ACK, 1, 1, 1);
+ Mockito.reset(tbClusterService, auditLogService);
alarm = updatedAlarm;
alarm.setCleared(true);
@@ -170,8 +172,10 @@ public class AlarmControllerTest extends AbstractControllerTest {
Assert.assertEquals(alarm.getClearTs(), updatedAlarm.getClearTs());
foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class);
- testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
- tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_CLEAR);
+
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId,
+ customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_CLEAR, 1, 1, 1);
+ Mockito.reset(tbClusterService, auditLogService);
alarm = updatedAlarm;
alarm.setAssigneeId(tenantAdminUserId);
@@ -182,8 +186,10 @@ public class AlarmControllerTest extends AbstractControllerTest {
Assert.assertEquals(alarm.getAssignTs(), updatedAlarm.getAssignTs());
foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class);
- testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
- tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGNED);
+
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId,
+ customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGNED, 1, 1, 1);
+ Mockito.reset(tbClusterService, auditLogService);
alarm = updatedAlarm;
alarm.setAssigneeId(null);
@@ -194,8 +200,11 @@ public class AlarmControllerTest extends AbstractControllerTest {
Assert.assertEquals(alarm.getAssignTs(), updatedAlarm.getAssignTs());
foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class);
- testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
- tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_UNASSIGNED);
+
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId,
+ customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_UNASSIGNED, 1, 1, 1);
+ Mockito.reset(tbClusterService, auditLogService);
+
}
@Test
@@ -241,7 +250,7 @@ public class AlarmControllerTest extends AbstractControllerTest {
doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isOk());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(new Alarm(alarm), alarm.getId(), alarm.getOriginator(),
+ testNotifyEntityAllOneTime(new Alarm(alarm), alarm.getId(), alarm.getOriginator(),
tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED);
}
@@ -254,7 +263,7 @@ public class AlarmControllerTest extends AbstractControllerTest {
doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isOk());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(new Alarm(alarm), alarm.getId(), alarm.getOriginator(),
+ testNotifyEntityAllOneTime(new Alarm(alarm), alarm.getId(), alarm.getOriginator(),
tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED);
}
@@ -531,6 +540,55 @@ public class AlarmControllerTest extends AbstractControllerTest {
tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_UNASSIGNED);
}
+ @Test
+ public void testUnassignTenantUserAlarmOnUserRemoving() throws Exception {
+ loginDifferentTenant();
+
+ User user = new User();
+ user.setAuthority(Authority.TENANT_ADMIN);
+ user.setTenantId(tenantId);
+ user.setEmail("tenantForAssign@thingsboard.org");
+ User savedUser = createUser(user, "password");
+
+ Device device = createDevice("Different tenant device", "default", "differentTenantTest");
+
+ Alarm alarm = Alarm.builder()
+ .type(TEST_ALARM_TYPE)
+ .tenantId(savedDifferentTenant.getId())
+ .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);
+
+ loginSysAdmin();
+
+ doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk());
+
+ loginDifferentTenant();
+
+ foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class);
+ Assert.assertNotNull(foundAlarm);
+ Assert.assertNull(foundAlarm.getAssigneeId());
+ Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs);
+ }
+
@Test
public void testUnassignAlarmOnUserRemoving() throws Exception {
loginDifferentTenant();
diff --git a/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java
index 40b1707271..88a8b939b8 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java
@@ -50,7 +50,6 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
@@ -114,8 +113,8 @@ public class AssetControllerTest extends AbstractControllerTest {
Asset savedAsset = doPost("/api/asset", asset, Asset.class);
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED);
+ testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(),
+ tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED);
Assert.assertNotNull(savedAsset);
Assert.assertNotNull(savedAsset.getId());
@@ -130,8 +129,8 @@ public class AssetControllerTest extends AbstractControllerTest {
savedAsset.setName("My new asset");
doPost("/api/asset", savedAsset, Asset.class);
- testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED);
+ testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(),
+ tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED);
Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(foundAsset.getName(), savedAsset.getName());
@@ -229,7 +228,8 @@ public class AssetControllerTest extends AbstractControllerTest {
@Test
public void testFindAssetTypesByTenantId() throws Exception {
- List assets = new ArrayList<>();
+ AssetProfile assetProfile = createAssetProfile("typeB");
+ assetProfile = doPost("/api/assetProfile", assetProfile, AssetProfile.class);
Mockito.reset(tbClusterService, auditLogService);
@@ -238,24 +238,25 @@ public class AssetControllerTest extends AbstractControllerTest {
Asset asset = new Asset();
asset.setName("My asset B" + i);
asset.setType("typeB");
- assets.add(doPost("/api/asset", asset, Asset.class));
+ asset.setAssetProfileId(assetProfile.getId());
+ doPost("/api/asset", asset, Asset.class);
}
- testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Asset(), new Asset(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Asset(), new Asset(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, cntTime);
+ ActionType.ADDED, cntTime, cntTime, cntTime);
for (int i = 0; i < 7; i++) {
Asset asset = new Asset();
asset.setName("My asset C" + i);
asset.setType("typeC");
- assets.add(doPost("/api/asset", asset, Asset.class));
+ doPost("/api/asset", asset, Asset.class);
}
for (int i = 0; i < 9; i++) {
Asset asset = new Asset();
asset.setName("My asset A" + i);
asset.setType("typeA");
- assets.add(doPost("/api/asset", asset, Asset.class));
+ doPost("/api/asset", asset, Asset.class);
}
List assetTypes = doGetTyped("/api/asset/types",
new TypeReference>() {
@@ -280,7 +281,7 @@ public class AssetControllerTest extends AbstractControllerTest {
doDelete("/api/asset/" + savedAsset.getId().getId().toString())
.andExpect(status().isOk());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(),
+ testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, savedAsset.getId().getId().toString());
@@ -342,7 +343,7 @@ public class AssetControllerTest extends AbstractControllerTest {
Asset savedAsset = doPost("/api/asset", asset, Asset.class);
Assert.assertEquals("default", savedAsset.getType());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(),
+ testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
}
@@ -380,9 +381,9 @@ public class AssetControllerTest extends AbstractControllerTest {
+ "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(savedCustomer.getId(), assignedAsset.getCustomerId());
- testNotifyEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(),
savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ASSIGNED_TO_CUSTOMER, assignedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle());
+ ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, assignedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle());
Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(savedCustomer.getId(), foundAsset.getCustomerId());
@@ -393,9 +394,9 @@ public class AssetControllerTest extends AbstractControllerTest {
doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId());
- testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.UNASSIGNED_FROM_CUSTOMER, savedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle());
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, savedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle());
foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId());
@@ -415,9 +416,10 @@ public class AssetControllerTest extends AbstractControllerTest {
Customer publicCustomer = doGet("/api/customer/" + assignedAsset.getCustomerId(), Customer.class);
Assert.assertTrue(publicCustomer.isPublic());
- testNotifyEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(),
savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ASSIGNED_TO_CUSTOMER, assignedAsset.getId().toString(), publicCustomer.getId().toString(), publicCustomer.getTitle());
+ ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, assignedAsset.getId().toString(),
+ publicCustomer.getId().toString(), publicCustomer.getTitle());
Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(publicCustomer.getId(), foundAsset.getCustomerId());
@@ -428,9 +430,10 @@ public class AssetControllerTest extends AbstractControllerTest {
doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId());
- testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(),
savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.UNASSIGNED_FROM_CUSTOMER, savedAsset.getId().toString(), publicCustomer.getId().toString(), publicCustomer.getTitle());
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, savedAsset.getId().toString(),
+ publicCustomer.getId().toString(), publicCustomer.getTitle());
foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId());
@@ -513,7 +516,7 @@ public class AssetControllerTest extends AbstractControllerTest {
}
List loadedAssets = new ArrayList<>();
PageLink pageLink = new PageLink(23);
- PageData pageData = null;
+ PageData pageData;
do {
pageData = doGetTypedWithPageLink("/api/tenant/assets?",
new TypeReference>() {
@@ -524,14 +527,14 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Asset(), new Asset(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Asset(), new Asset(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
loadedAssets.removeIf(asset -> asset.getType().equals(DefaultRuleEngineStatisticsService.TB_SERVICE_QUEUE));
- Collections.sort(assets, idComparator);
- Collections.sort(loadedAssets, idComparator);
+ assets.sort(idComparator);
+ loadedAssets.sort(idComparator);
Assert.assertEquals(assets, loadedAssets);
}
@@ -574,8 +577,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsTitle1, idComparator);
- Collections.sort(loadedAssetsTitle1, idComparator);
+ assetsTitle1.sort(idComparator);
+ loadedAssetsTitle1.sort(idComparator);
Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
@@ -591,8 +594,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsTitle2, idComparator);
- Collections.sort(loadedAssetsTitle2, idComparator);
+ assetsTitle2.sort(idComparator);
+ loadedAssetsTitle2.sort(idComparator);
Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
@@ -661,8 +664,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsType1, idComparator);
- Collections.sort(loadedAssetsType1, idComparator);
+ assetsType1.sort(idComparator);
+ loadedAssetsType1.sort(idComparator);
Assert.assertEquals(assetsType1, loadedAssetsType1);
@@ -678,8 +681,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsType2, idComparator);
- Collections.sort(loadedAssetsType2, idComparator);
+ assetsType2.sort(idComparator);
+ loadedAssetsType2.sort(idComparator);
Assert.assertEquals(assetsType2, loadedAssetsType2);
@@ -738,8 +741,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assets, idComparator);
- Collections.sort(loadedAssets, idComparator);
+ assets.sort(idComparator);
+ loadedAssets.sort(idComparator);
Assert.assertEquals(assets, loadedAssets);
}
@@ -791,8 +794,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsTitle1, idComparator);
- Collections.sort(loadedAssetsTitle1, idComparator);
+ assetsTitle1.sort(idComparator);
+ loadedAssetsTitle1.sort(idComparator);
Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
@@ -808,8 +811,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsTitle2, idComparator);
- Collections.sort(loadedAssetsTitle2, idComparator);
+ assetsTitle2.sort(idComparator);
+ loadedAssetsTitle2.sort(idComparator);
Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
@@ -887,8 +890,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsType1, idComparator);
- Collections.sort(loadedAssetsType1, idComparator);
+ assetsType1.sort(idComparator);
+ loadedAssetsType1.sort(idComparator);
Assert.assertEquals(assetsType1, loadedAssetsType1);
@@ -904,8 +907,8 @@ public class AssetControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(assetsType2, idComparator);
- Collections.sort(loadedAssetsType2, idComparator);
+ assetsType2.sort(idComparator);
+ loadedAssetsType2.sort(idComparator);
Assert.assertEquals(assetsType2, loadedAssetsType2);
diff --git a/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java
index c84b058cc7..38420c3e32 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java
@@ -355,7 +355,7 @@ public class AssetProfileControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new AssetProfile(), new AssetProfile(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
Mockito.reset(tbClusterService, auditLogService);
List loadedAssetProfiles = new ArrayList<>();
@@ -384,7 +384,7 @@ public class AssetProfileControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(loadedAssetProfiles.get(0), loadedAssetProfiles.get(0),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedAssetProfiles.get(0).getId().getId().toString());
+ ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedAssetProfiles.get(0).getId().getId().toString());
pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/assetProfiles?",
diff --git a/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java
index 125e533471..f5c33debb2 100644
--- a/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java
@@ -117,8 +117,8 @@ public class CustomerControllerTest extends AbstractControllerTest {
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), savedCustomer.getId(),
- savedCustomer.getTenantId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
+ testNotifyEntityAllOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(),
+ new CustomerId(CustomerId.NULL_UUID), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
Assert.assertNotNull(savedCustomer);
@@ -242,7 +242,7 @@ public class CustomerControllerTest extends AbstractControllerTest {
doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
.andExpect(status().isOk());
- testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
+ testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedCustomer, savedCustomer.getId(),
savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
}
@@ -272,7 +272,7 @@ public class CustomerControllerTest extends AbstractControllerTest {
doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
.andExpect(status().isOk());
- testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
+ testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedCustomer, savedCustomer.getId(),
savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
@@ -332,9 +332,9 @@ public class CustomerControllerTest extends AbstractControllerTest {
}
List customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
- testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Customer(), new Customer(),
tenantId, tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
List loadedCustomers = new ArrayList<>(135);
PageLink pageLink = new PageLink(23);
diff --git a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java
index 9f8e63e3b0..6f0d6f9465 100644
--- a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java
@@ -46,7 +46,6 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
@@ -154,7 +153,7 @@ public class DashboardControllerTest extends AbstractControllerTest {
doDelete("/api/dashboard/" + savedDashboard.getId().getId().toString()).andExpect(status().isOk());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDashboard, savedDashboard.getId(), savedDashboard.getId(),
+ testNotifyEntityAllOneTime(savedDashboard, savedDashboard.getId(), savedDashboard.getId(),
savedDashboard.getTenantId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED,
savedDashboard.getId().getId().toString());
@@ -198,7 +197,7 @@ public class DashboardControllerTest extends AbstractControllerTest {
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(),
savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
- assignedDashboard .getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
+ ActionType.UPDATED, assignedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo()));
@@ -210,7 +209,7 @@ public class DashboardControllerTest extends AbstractControllerTest {
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(),
savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
- unassignedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
+ ActionType.UPDATED, unassignedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty());
@@ -241,7 +240,7 @@ public class DashboardControllerTest extends AbstractControllerTest {
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(),
savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
- assignedDashboard .getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle());
+ ActionType.UPDATED, assignedDashboard .getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle());
Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(publicCustomer.toShortCustomerInfo()));
@@ -253,7 +252,7 @@ public class DashboardControllerTest extends AbstractControllerTest {
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(),
savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
- unassignedDashboard.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle());
+ ActionType.UPDATED, unassignedDashboard.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle());
Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty());
@@ -339,9 +338,9 @@ public class DashboardControllerTest extends AbstractControllerTest {
dashboards.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class)));
}
- testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Dashboard(), new Dashboard(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Dashboard(), new Dashboard(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
List loadedDashboards = new ArrayList<>();
PageLink pageLink = new PageLink(24);
@@ -356,8 +355,8 @@ public class DashboardControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(dashboards, idComparator);
- Collections.sort(loadedDashboards, idComparator);
+ dashboards.sort(idComparator);
+ loadedDashboards.sort(idComparator);
Assert.assertEquals(dashboards, loadedDashboards);
}
@@ -400,8 +399,8 @@ public class DashboardControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(dashboardsTitle1, idComparator);
- Collections.sort(loadedDashboardsTitle1, idComparator);
+ dashboardsTitle1.sort(idComparator);
+ loadedDashboardsTitle1.sort(idComparator);
Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1);
@@ -417,8 +416,8 @@ public class DashboardControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(dashboardsTitle2, idComparator);
- Collections.sort(loadedDashboardsTitle2, idComparator);
+ dashboardsTitle2.sort(idComparator);
+ loadedDashboardsTitle2.sort(idComparator);
Assert.assertEquals(dashboardsTitle2, loadedDashboardsTitle2);
@@ -429,9 +428,9 @@ public class DashboardControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
}
- testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Dashboard(), new Dashboard(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Dashboard(), new Dashboard(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.DELETED, cntEntity, 1);
+ ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity, 1);
pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/dashboards?",
@@ -474,7 +473,7 @@ public class DashboardControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Dashboard(), new Dashboard(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity*2);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity*2);
List loadedDashboards = new ArrayList<>();
PageLink pageLink = new PageLink(21);
@@ -489,8 +488,8 @@ public class DashboardControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(dashboards, idComparator);
- Collections.sort(loadedDashboards, idComparator);
+ dashboards.sort(idComparator);
+ loadedDashboards.sort(idComparator);
Assert.assertEquals(dashboards, loadedDashboards);
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java
new file mode 100644
index 0000000000..36a4365544
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java
@@ -0,0 +1,340 @@
+/**
+ * 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.controller;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.AdditionalAnswers;
+import org.mockito.Mockito;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.common.util.ThingsBoardExecutors;
+import org.thingsboard.server.common.data.Device;
+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.Tenant;
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
+import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
+import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
+import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
+import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
+import org.thingsboard.server.common.data.id.DeviceProfileId;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.security.Authority;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.common.data.security.DeviceCredentialsType;
+import org.thingsboard.server.dao.device.DeviceDao;
+import org.thingsboard.server.dao.service.DaoSqlTest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS;
+
+@TestPropertySource(properties = {
+ "device.connectivity.https.enabled=true",
+ "device.connectivity.mqtts.enabled=true",
+ "device.connectivity.coaps.enabled=true",
+})
+@ContextConfiguration(classes = {DeviceConnectivityControllerTest.Config.class})
+@DaoSqlTest
+public class DeviceConnectivityControllerTest extends AbstractControllerTest {
+ static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {
+ };
+
+ private static final String DEVICE_TELEMETRY_TOPIC = "v1/devices/customTopic";
+ private static final String CHECK_DOCUMENTATION = "Check documentation";
+
+ ListeningExecutorService executor;
+
+ private Tenant savedTenant;
+ private User tenantAdmin;
+ private DeviceProfileId mqttDeviceProfileId;
+ private DeviceProfileId coapDeviceProfileId;
+
+ static class Config {
+ @Bean
+ @Primary
+ public DeviceDao deviceDao(DeviceDao deviceDao) {
+ return Mockito.mock(DeviceDao.class, AdditionalAnswers.delegatesTo(deviceDao));
+ }
+ }
+
+ @Before
+ public void beforeTest() throws Exception {
+ executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
+
+ loginSysAdmin();
+
+ Tenant tenant = new Tenant();
+ tenant.setTitle("My tenant");
+ savedTenant = doPost("/api/tenant", tenant, Tenant.class);
+ Assert.assertNotNull(savedTenant);
+
+ tenantAdmin = new User();
+ tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
+ tenantAdmin.setTenantId(savedTenant.getId());
+ tenantAdmin.setEmail("tenant2@thingsboard.org");
+ tenantAdmin.setFirstName("Joe");
+ tenantAdmin.setLastName("Downs");
+
+ tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
+
+ DeviceProfile mqttProfile = new DeviceProfile();
+ mqttProfile.setName("Mqtt device profile");
+ mqttProfile.setType(DeviceProfileType.DEFAULT);
+ mqttProfile.setTransportType(DeviceTransportType.MQTT);
+ DeviceProfileData deviceProfileData = new DeviceProfileData();
+ deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration());
+ MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration();
+ transportConfiguration.setDeviceTelemetryTopic(DEVICE_TELEMETRY_TOPIC);
+ deviceProfileData.setTransportConfiguration(transportConfiguration);
+ mqttProfile.setProfileData(deviceProfileData);
+ mqttProfile.setDefault(false);
+ mqttProfile.setDefaultRuleChainId(null);
+
+ mqttDeviceProfileId = doPost("/api/deviceProfile", mqttProfile, DeviceProfile.class).getId();
+
+ DeviceProfile coapProfile = new DeviceProfile();
+ coapProfile.setName("Coap device profile");
+ coapProfile.setType(DeviceProfileType.DEFAULT);
+ coapProfile.setTransportType(DeviceTransportType.COAP);
+ DeviceProfileData deviceProfileData2 = new DeviceProfileData();
+ deviceProfileData2.setConfiguration(new DefaultDeviceProfileConfiguration());
+ deviceProfileData2.setTransportConfiguration(new CoapDeviceProfileTransportConfiguration());
+ coapProfile.setProfileData(deviceProfileData);
+ coapProfile.setDefault(false);
+ coapProfile.setDefaultRuleChainId(null);
+
+ coapDeviceProfileId = doPost("/api/deviceProfile", coapProfile, DeviceProfile.class).getId();
+ }
+
+ @After
+ public void afterTest() throws Exception {
+ executor.shutdownNow();
+
+ loginSysAdmin();
+
+ doDelete("/api/tenant/" + savedTenant.getId().getId())
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void testFetchPublishTelemetryCommandsForDefaultDevice() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setType("default");
+ Device savedDevice = doPost("/api/device", device, Device.class);
+ JsonNode commands =
+ doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {
+ });
+
+ DeviceCredentials credentials =
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
+
+ assertThat(commands).hasSize(3);
+ JsonNode httpCommands = commands.get(HTTP);
+ assertThat(httpCommands.get(HTTP).asText()).isEqualTo(String.format("curl -v -X POST http://localhost:8080/api/v1/%s/telemetry " +
+ "--header Content-Type:application/json --data \"{temperature:25}\"",
+ credentials.getCredentialsId()));
+ assertThat(httpCommands.get(HTTPS).asText()).isEqualTo(String.format("curl -v -X POST https://localhost:443/api/v1/%s/telemetry " +
+ "--header Content-Type:application/json --data \"{temperature:25}\"",
+ credentials.getCredentialsId()));
+
+
+ JsonNode mqttCommands = commands.get(MQTT);
+ assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " +
+ "-u %s -m \"{temperature:25}\"",
+ credentials.getCredentialsId()));
+ assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download");
+ assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " +
+ "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId()));
+
+ JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER);
+ assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" +
+ " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"",
+ credentials.getCredentialsId()));
+ assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " +
+ "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " +
+ "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"",
+ credentials.getCredentialsId()));
+
+ JsonNode linuxCoapCommands = commands.get(COAP);
+ assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry " +
+ "-t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
+ assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry" +
+ " -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
+ }
+
+ @Test
+ public void testFetchPublishTelemetryCommandsForMqttDeviceWithAccessToken() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setDeviceProfileId(mqttDeviceProfileId);
+
+ Device savedDevice = doPost("/api/device", device, Device.class);
+ DeviceCredentials credentials =
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
+
+ JsonNode commands =
+ doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {
+ });
+ assertThat(commands).hasSize(1);
+
+ JsonNode mqttCommands = commands.get(MQTT);
+ assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " +
+ "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId()));
+ assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download");
+ assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " +
+ "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId()));
+
+ JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER);
+ assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" +
+ " -p 1883 -t %s -u %s -m \"{temperature:25}\"",
+ DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId()));
+ assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " +
+ "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " +
+ "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"",
+ DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId()));
+ }
+
+ @Test
+ public void testFetchPublishTelemetryCommandsForDeviceWithMqttBasicCreds() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setDeviceProfileId(mqttDeviceProfileId);
+
+ Device savedDevice = doPost("/api/device", device, Device.class);
+ DeviceCredentials credentials =
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
+ credentials.setCredentialsId(null);
+ credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC);
+ BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials();
+ String clientId = "testClientId";
+ String userName = "testUsername";
+ String password = "testPassword";
+ basicMqttCredentials.setClientId(clientId);
+ basicMqttCredentials.setUserName(userName);
+ basicMqttCredentials.setPassword(password);
+ credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials));
+ doPost("/api/device/credentials", credentials)
+ .andExpect(status().isOk());
+
+ JsonNode commands =
+ doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {
+ });
+ assertThat(commands).hasSize(1);
+
+ JsonNode mqttCommands = commands.get(MQTT);
+ assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " +
+ "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password));
+ assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download");
+ assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " +
+ "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password));
+
+ JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER);
+ assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" +
+ " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"",
+ DEVICE_TELEMETRY_TOPIC, clientId, userName, password));
+ assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " +
+ "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " +
+ "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"",
+ DEVICE_TELEMETRY_TOPIC, clientId, userName, password));
+ }
+
+ @Test
+ public void testFetchPublishTelemetryCommandsForDeviceWithX509Creds() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setDeviceProfileId(mqttDeviceProfileId);
+
+ Device savedDevice = doPost("/api/device", device, Device.class);
+ DeviceCredentials credentials =
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
+ credentials.setCredentialsId(null);
+ credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE);
+ credentials.setCredentialsValue("testValue");
+ doPost("/api/device/credentials", credentials)
+ .andExpect(status().isOk());
+
+ JsonNode commands =
+ doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {
+ });
+ assertThat(commands).hasSize(1);
+ assertThat(commands.get(MQTT).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION);
+ assertThat(commands.get(MQTT).get(DOCKER)).isNull();
+ }
+
+ @Test
+ public void testFetchPublishTelemetryCommandsForCoapDevice() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setDeviceProfileId(coapDeviceProfileId);
+
+ Device savedDevice = doPost("/api/device", device, Device.class);
+ DeviceCredentials credentials =
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
+
+ JsonNode commands =
+ doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {
+ });
+ assertThat(commands).hasSize(1);
+
+ JsonNode linuxCommands = commands.get(COAP);
+ assertThat(linuxCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"",
+ credentials.getCredentialsId()));
+ assertThat(linuxCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"",
+ credentials.getCredentialsId()));
+ }
+
+ @Test
+ public void testFetchPublishTelemetryCommandsForCoapDeviceWithX509Creds() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setDeviceProfileId(coapDeviceProfileId);
+
+ Device savedDevice = doPost("/api/device", device, Device.class);
+ DeviceCredentials credentials =
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
+ credentials.setCredentialsId(null);
+ credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE);
+ credentials.setCredentialsValue("testValue");
+ doPost("/api/device/credentials", credentials)
+ .andExpect(status().isOk());
+
+ JsonNode commands =
+ doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {
+ });
+ assertThat(commands).hasSize(1);
+ assertThat(commands.get(COAP).get(COAPS).asText()).isEqualTo(CHECK_DOCUMENTATION);
+ }
+}
diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
index 1c952bd549..5cc9c3dc91 100644
--- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
@@ -156,9 +156,8 @@ public class DeviceControllerTest extends AbstractControllerTest {
Device oldDevice = new Device(savedDevice);
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED);
+ testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
+ tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED);
testNotificationUpdateGatewayNever();
Assert.assertNotNull(savedDevice);
@@ -212,7 +211,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
Device oldDevice = new Device(savedDevice);
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
+ testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
testNotificationUpdateGatewayNever();
@@ -436,6 +435,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
@Test
public void testFindDeviceTypesByTenantId() throws Exception {
+ DeviceProfile deviceProfile = createDeviceProfile("typeB");
+ deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
+
List devices = new ArrayList<>();
int cntEntity = 3;
@@ -446,12 +448,13 @@ public class DeviceControllerTest extends AbstractControllerTest {
Device device = new Device();
device.setName("My device B" + i);
device.setType("typeB");
+ device.setDeviceProfileId(deviceProfile.getId());
devices.add(doPost("/api/device", device, Device.class));
}
- testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
testNotificationUpdateGatewayNever();
for (int i = 0; i < 7; i++) {
@@ -491,7 +494,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
doDelete("/api/device/" + savedDevice.getId().getId())
.andExpect(status().isOk());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
+ testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedDevice.getId().getId().toString());
testNotificationDeleteGatewayOneTime(savedDevice);
@@ -511,7 +514,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
Device savedDevice = doPost("/api/device", device, Device.class);
Assert.assertEquals("default", savedDevice.getType());
- testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
+ testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
testNotificationUpdateGatewayNever();
@@ -551,9 +554,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
+ "/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId());
- testNotifyEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(),
savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
- assignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(),
+ ActionType.UPDATED, assignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(),
savedCustomer.getTitle());
testNotificationUpdateGatewayNever();
@@ -566,9 +569,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
doDelete("/api/customer/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId());
- testNotifyEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(),
savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
- unassignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(),
+ ActionType.UPDATED, unassignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(),
savedCustomer.getTitle());
testNotificationDeleteGatewayNever();
@@ -590,9 +593,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
Customer publicCustomer = doGet("/api/customer/" + assignedDevice.getCustomerId(), Customer.class);
Assert.assertTrue(publicCustomer.isPublic());
- testNotifyEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(),
publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
- assignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(),
+ ActionType.UPDATED, assignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(),
publicCustomer.getTitle());
testNotificationUpdateGatewayNever();
@@ -605,9 +608,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
doDelete("/api/customer/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId());
- testNotifyEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(),
publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
- unassignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(),
+ ActionType.UPDATED, unassignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(),
publicCustomer.getTitle());
testNotificationDeleteGatewayNever();
@@ -842,9 +845,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
List devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
- testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
testNotificationUpdateGatewayNever();
List loadedDevices = new ArrayList<>(cntEntity);
@@ -865,9 +868,9 @@ public class DeviceControllerTest extends AbstractControllerTest {
deleteEntitiesAsync("/api/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
- testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Device(), new Device(),
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.DELETED, cntEntity, 1);
+ ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity,1);
testNotificationUpdateGatewayNever();
}
@@ -1052,7 +1055,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity * 2);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
testNotificationUpdateGatewayNever();
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
@@ -1074,7 +1077,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Device(), new Device(),
savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3);
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, cntEntity, cntEntity, 3);
testNotificationUpdateGatewayNever();
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java
index d2bcfe2b88..14b052d93c 100644
--- a/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java
@@ -498,7 +498,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new DeviceProfile(), new DeviceProfile(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
Mockito.reset(tbClusterService, auditLogService);
List loadedDeviceProfiles = new ArrayList<>();
@@ -527,7 +527,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(loadedDeviceProfiles.get(0), loadedDeviceProfiles.get(0),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedDeviceProfiles.get(0).getId().getId().toString());
+ ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedDeviceProfiles.get(0).getId().getId().toString());
pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/deviceProfiles?",
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 c8a20a38f5..78729eecf1 100644
--- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java
@@ -21,6 +21,7 @@ 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 com.google.protobuf.AbstractMessage;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -45,7 +46,6 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
-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.common.data.security.Authority;
@@ -62,6 +62,8 @@ import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg;
+import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
@@ -77,6 +79,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@TestPropertySource(properties = {
"edges.enabled=true",
+ "queue.rule-engine.stats.enabled=false"
})
@ContextConfiguration(classes = {EdgeControllerTest.Config.class})
@DaoSqlTest
@@ -87,10 +90,6 @@ public class EdgeControllerTest extends AbstractControllerTest {
private IdComparator idComparator = new IdComparator<>();
- private Tenant savedTenant;
- private TenantId tenantId;
- private User tenantAdmin;
-
ListeningExecutorService executor;
List> futures;
@@ -107,35 +106,14 @@ public class EdgeControllerTest extends AbstractControllerTest {
}
@Before
- public void beforeTest() throws Exception {
+ public void setupEdgeTest() throws Exception {
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
-
- loginSysAdmin();
-
- Tenant tenant = new Tenant();
- tenant.setTitle("My tenant for Edge");
- savedTenant = doPost("/api/tenant", tenant, Tenant.class);
- tenantId = savedTenant.getId();
- Assert.assertNotNull(savedTenant);
-
- tenantAdmin = new User();
- tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
- tenantAdmin.setTenantId(savedTenant.getId());
- tenantAdmin.setEmail("tenant2@thingsboard.org");
- tenantAdmin.setFirstName("Joe");
- tenantAdmin.setLastName("Downs");
-
- tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
+ loginTenantAdmin();
}
@After
- public void afterTest() throws Exception {
+ public void teardownEdgeTest() throws Exception {
executor.shutdownNow();
-
- loginSysAdmin();
-
- doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
- .andExpect(status().isOk());
}
@Test
@@ -149,13 +127,13 @@ public class EdgeControllerTest extends AbstractControllerTest {
Assert.assertNotNull(savedEdge);
Assert.assertNotNull(savedEdge.getId());
Assert.assertTrue(savedEdge.getCreatedTime() > 0);
- Assert.assertEquals(savedTenant.getId(), savedEdge.getTenantId());
+ Assert.assertEquals(tenantId, savedEdge.getTenantId());
Assert.assertNotNull(savedEdge.getCustomerId());
Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId());
Assert.assertEquals(edge.getName(), savedEdge.getName());
testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedEdge, savedEdge.getId(), savedEdge.getId(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
+ tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(),
ActionType.ADDED);
savedEdge.setName("My new edge");
@@ -165,7 +143,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
Assert.assertEquals(foundEdge.getName(), savedEdge.getName());
testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(foundEdge, foundEdge.getId(), foundEdge.getId(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
+ tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(),
ActionType.UPDATED);
}
@@ -180,8 +158,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
- testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(),
- tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
+ testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId,
+ tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
Mockito.reset(tbClusterService, auditLogService);
msgError = msgErrorFieldLength("type");
@@ -191,8 +169,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
- testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(),
- tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
+ testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId,
+ tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
Mockito.reset(tbClusterService, auditLogService);
msgError = msgErrorFieldLength("label");
@@ -202,8 +180,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
- testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(),
- tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
+ testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId,
+ tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
}
@Test
@@ -229,7 +207,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
}
testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Edge(), new Edge(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
+ tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(),
ActionType.ADDED, cntEntity, 0);
for (int i = 0; i < 7; i++) {
@@ -262,7 +240,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedEdge, savedEdge.getId(), savedEdge.getId(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
+ tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(),
ActionType.DELETED, savedEdge.getId().getId().toString());
doGet("/api/edge/" + savedEdge.getId().getId().toString())
@@ -281,8 +259,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
- testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(),
- tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
+ testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId,
+ tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
}
@Test
@@ -296,8 +274,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
- testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(),
- tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
+ testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId,
+ tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
}
@Test
@@ -316,8 +294,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedCustomer.getId(), assignedEdge.getCustomerId());
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedEdge, assignedEdge.getId(), assignedEdge.getId(),
- savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
- assignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
+ tenantId, savedCustomer.getId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
+ ActionType.ASSIGNED_TO_CUSTOMER, assignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);
Assert.assertEquals(savedCustomer.getId(), foundEdge.getCustomerId());
@@ -327,8 +305,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedEdge.getCustomerId().getId());
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(unassignedEdge, unassignedEdge.getId(), unassignedEdge.getId(),
- savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
- unassignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
+ tenantId, savedCustomer.getId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
+ ActionType.UNASSIGNED_FROM_CUSTOMER, unassignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class);
Assert.assertEquals(ModelConstants.NULL_UUID, foundEdge.getCustomerId().getId());
@@ -375,7 +353,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
customer.setTitle("Different customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
- login(tenantAdmin.getEmail(), "testPassword1");
+ loginTenantAdmin();
Edge edge = constructEdge("My edge", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
@@ -625,8 +603,8 @@ public class EdgeControllerTest extends AbstractControllerTest {
List edges = new ArrayList<>(Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS));
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Edge(), new Edge(),
- savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2,
+ tenantId, customerId, tenantAdminUser.getId(), tenantAdminUser.getEmail(),
+ ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2,
new String(), new String(), new String());
List loadedEdges = new ArrayList<>();
@@ -731,7 +709,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
cntEntity = loadedEdgesTitle1.size();
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Edge(), new Edge(),
- savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(),
+ tenantId, customerId, tenantAdminUser.getId(), tenantAdminUser.getEmail(),
ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3);
pageLink = new PageLink(4, 0, title1);
@@ -857,56 +835,45 @@ public class EdgeControllerTest extends AbstractControllerTest {
@Test
public void testSyncEdge() throws Exception {
- Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class);
+ Asset asset = new Asset();
+ asset.setName("Test Sync Edge Asset 1");
+ asset.setType("test");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
Device device = new Device();
device.setName("Test Sync Edge Device 1");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
+
+ Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class);
+
doPost("/api/edge/" + edge.getId().getId().toString()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class);
-
- Asset asset = new Asset();
- asset.setName("Test Sync Edge Asset 1");
- asset.setType("test");
- Asset savedAsset = doPost("/api/asset", asset, Asset.class);
doPost("/api/edge/" + edge.getId().getId().toString()
+ "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret());
edgeImitator.ignoreType(UserCredentialsUpdateMsg.class);
- edgeImitator.expectMessageAmount(20);
+ edgeImitator.expectMessageAmount(21);
edgeImitator.connect();
assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue();
- assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("one msg during sync process").hasSize(1);
- List ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class);
- assertThat(ruleChainUpdateMsgs).as("one msg during sync process, another from edge creation").hasSize(2);
- assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("one msg during sync process for 'default' device profile").hasSize(3);
- assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("one msg once device assigned to edge").hasSize(2);
- assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("two msgs during sync process for 'default' and 'test' asset profiles").hasSize(4);
- assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("two msgs - one during sync process, and one more once asset assigned to edge").hasSize(2);
- assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("one msg during sync process for tenant admin user").hasSize(1);
- assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update").hasSize(4);
- assertThat(edgeImitator.findAllMessagesByType(CustomerUpdateMsg.class)).as("one msg during sync process for 'Public' customer").hasSize(1);
- verifyRuleChainMsgsAreRoot(ruleChainUpdateMsgs);
-
- edgeImitator.expectMessageAmount(15);
+ verifyFetchersMsgs(edgeImitator);
+ // verify queue msgs
+ Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, "Edge Root Rule Chain"));
+ Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default"));
+ Assert.assertTrue(popDeviceMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Device 1"));
+ Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test"));
+ Assert.assertTrue(popAssetMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Asset 1"));
+ Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty());
+
+ edgeImitator.expectMessageAmount(16);
doPost("/api/edge/sync/" + edge.getId());
assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue();
- assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("queue msg").hasSize(1);
- ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class);
- assertThat(ruleChainUpdateMsgs).as("rule chain msg").hasSize(1);
- assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("device profile msg").hasSize(2);
- assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("asset profile msg").hasSize(3);
- assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("asset update msg").hasSize(1);
- assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("user update msg").hasSize(1);
- assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update msg").hasSize(4);
- assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("asset update msg").hasSize(1);
- assertThat(edgeImitator.findAllMessagesByType(CustomerUpdateMsg.class)).as("one msg during sync process for 'Public' customer").hasSize(1);
- verifyRuleChainMsgsAreRoot(ruleChainUpdateMsgs);
+ verifyFetchersMsgs(edgeImitator);
+ Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty());
edgeImitator.allowIgnoredTypes();
try {
@@ -922,23 +889,174 @@ public class EdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
}
- private void verifyRuleChainMsgsAreRoot(List ruleChainUpdateMsgs) {
- for (RuleChainUpdateMsg ruleChainUpdateMsg : ruleChainUpdateMsgs) {
- Assert.assertTrue(ruleChainUpdateMsg.getRoot());
+ private void verifyFetchersMsgs(EdgeImitator edgeImitator) {
+ Assert.assertTrue(popQueueMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Main"));
+ Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Edge Root Rule Chain"));
+ Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail", true));
+ Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail", false));
+ Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mailTemplates", true));
+ 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(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"));
+ Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default"));
+ Assert.assertTrue(popDeviceMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Device 1"));
+ Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test"));
+ Assert.assertTrue(popAssetMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Asset 1"));
+ Assert.assertTrue(popSyncCompletedMsg(edgeImitator.getDownlinkMsgs()));
+ }
+
+ private boolean popQueueMsg(List messages, UpdateMsgType msgType, String name) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof QueueUpdateMsg) {
+ QueueUpdateMsg queueUpdateMsg = (QueueUpdateMsg) message;
+ if (msgType.equals(queueUpdateMsg.getMsgType())
+ && name.equals(queueUpdateMsg.getName())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popRuleChainMsg(List messages, UpdateMsgType msgType, String name) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof RuleChainUpdateMsg) {
+ RuleChainUpdateMsg ruleChainUpdateMsg = (RuleChainUpdateMsg) message;
+ if (msgType.equals(ruleChainUpdateMsg.getMsgType())
+ && name.equals(ruleChainUpdateMsg.getName())
+ && ruleChainUpdateMsg.getRoot()) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popAdminSettingsMsg(List messages, String key, boolean isSystem) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof AdminSettingsUpdateMsg) {
+ AdminSettingsUpdateMsg adminSettingsUpdateMsg = (AdminSettingsUpdateMsg) message;
+ if (key.equals(adminSettingsUpdateMsg.getKey())
+ && isSystem == adminSettingsUpdateMsg.getIsSystem()) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popDeviceProfileMsg(List messages, UpdateMsgType msgType, String name) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof DeviceProfileUpdateMsg) {
+ DeviceProfileUpdateMsg deviceProfileUpdateMsg = (DeviceProfileUpdateMsg) message;
+ if (msgType.equals(deviceProfileUpdateMsg.getMsgType())
+ && name.equals(deviceProfileUpdateMsg.getName())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popDeviceMsg(List messages, UpdateMsgType msgType, String name) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof DeviceUpdateMsg) {
+ DeviceUpdateMsg deviceUpdateMsg = (DeviceUpdateMsg) message;
+ if (msgType.equals(deviceUpdateMsg.getMsgType())
+ && name.equals(deviceUpdateMsg.getName())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popAssetProfileMsg(List messages, UpdateMsgType msgType, String name) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof AssetProfileUpdateMsg) {
+ AssetProfileUpdateMsg assetProfileUpdateMsg = (AssetProfileUpdateMsg) message;
+ if (msgType.equals(assetProfileUpdateMsg.getMsgType())
+ && name.equals(assetProfileUpdateMsg.getName())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popAssetMsg(List messages, UpdateMsgType msgType, String name) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof AssetUpdateMsg) {
+ AssetUpdateMsg assetUpdateMsg = (AssetUpdateMsg) message;
+ if (msgType.equals(assetUpdateMsg.getMsgType())
+ && name.equals(assetUpdateMsg.getName())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popUserMsg(List messages, UpdateMsgType msgType, String email, Authority authority) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof UserUpdateMsg) {
+ UserUpdateMsg userUpdateMsg = (UserUpdateMsg) message;
+ if (msgType.equals(userUpdateMsg.getMsgType())
+ && email.equals(userUpdateMsg.getEmail())
+ && authority.name().equals(userUpdateMsg.getAuthority())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popCustomerMsg(List messages, UpdateMsgType msgType, String title) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof CustomerUpdateMsg) {
+ CustomerUpdateMsg customerUpdateMsg = (CustomerUpdateMsg) message;
+ if (msgType.equals(customerUpdateMsg.getMsgType())
+ && title.equals(customerUpdateMsg.getTitle())) {
+ messages.remove(message);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean popSyncCompletedMsg(List messages) {
+ for (AbstractMessage message : messages) {
+ if (message instanceof SyncCompletedMsg) {
+ messages.remove(message);
+ return true;
+ }
}
+ return false;
}
@Test
public void testDeleteEdgeWithDeleteRelationsOk() throws Exception {
EdgeId edgeId = savedEdge("Edge for Test WithRelationsOk").getId();
- testEntityDaoWithRelationsOk(savedTenant.getId(), edgeId, "/api/edge/" + edgeId);
+ testEntityDaoWithRelationsOk(tenantId, edgeId, "/api/edge/" + edgeId);
}
@Ignore
@Test
public void testDeleteEdgeExceptionWithRelationsTransactional() throws Exception {
EdgeId edgeId = savedEdge("Edge for Test WithRelations Transactional Exception").getId();
- testEntityDaoWithRelationsTransactionalException(edgeDao, savedTenant.getId(), edgeId, "/api/edge/" + edgeId);
+ testEntityDaoWithRelationsTransactionalException(edgeDao, tenantId, edgeId, "/api/edge/" + edgeId);
}
private Edge savedEdge(String name) {
diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java
index 255aa2bdf1..04842df6a0 100644
--- a/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java
@@ -27,8 +27,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.Device;
-import org.thingsboard.server.common.data.Tenant;
-import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@@ -38,7 +36,6 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
-import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.edge.EdgeEventDao;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository;
@@ -54,18 +51,15 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@TestPropertySource(properties = {
"edges.enabled=true",
+ "queue.rule-engine.stats.enabled=false"
})
@Slf4j
@DaoSqlTest
public class EdgeEventControllerTest extends AbstractControllerTest {
- private Tenant savedTenant;
- private User tenantAdmin;
-
@Autowired
private EdgeEventDao edgeEventDao;
@SpyBean
@@ -80,33 +74,11 @@ public class EdgeEventControllerTest extends AbstractControllerTest {
@Before
public void beforeTest() throws Exception {
- loginSysAdmin();
-
- Tenant tenant = new Tenant();
- tenant.setTitle("My tenant");
- savedTenant = doPost("/api/tenant", tenant, Tenant.class);
- Assert.assertNotNull(savedTenant);
-
- tenantAdmin = new User();
- tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
- tenantAdmin.setTenantId(savedTenant.getId());
- tenantAdmin.setEmail("tenant2@thingsboard.org");
- tenantAdmin.setFirstName("Joe");
- tenantAdmin.setLastName("Downs");
-
- tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
- // sleep 1 seconds to avoid CREDENTIALS updated message for the user
- // user credentials is going to be stored and updated event pushed to edge notification service
- // while service will be processing this event edge could be already added and additional message will be pushed
- Thread.sleep(1000);
+ loginTenantAdmin();
}
@After
public void afterTest() throws Exception {
- loginSysAdmin();
-
- doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
- .andExpect(status().isOk());
}
@Test
@@ -127,19 +99,37 @@ public class EdgeEventControllerTest extends AbstractControllerTest {
EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE);
+ awaitForNumberOfEdgeEvents(edgeId, 3);
+
doPost("/api/relation", relation);
+ awaitForNumberOfEdgeEvents(edgeId, 4);
+
+ List edgeEvents = findEdgeEvents(edgeId);
+ Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.RULE_CHAIN)); // root rule chain
+ Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.DEVICE)); // TestDevice
+ Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.ASSET)); // TestAsset
+ Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.RELATION));
+ Assert.assertTrue(edgeEvents.isEmpty());
+ }
+
+ private boolean popEdgeEvent(List edgeEvents, EdgeEventType edgeEventType) {
+ for (EdgeEvent edgeEvent : edgeEvents) {
+ if (edgeEventType.equals(edgeEvent.getType())) {
+ edgeEvents.remove(edgeEvent);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void awaitForNumberOfEdgeEvents(EdgeId edgeId, int expectedNumber) {
Awaitility.await()
.atMost(30, TimeUnit.SECONDS)
.until(() -> {
List edgeEvents = findEdgeEvents(edgeId);
- return edgeEvents.size() == 4;
+ return edgeEvents.size() == expectedNumber;
});
- List edgeEvents = findEdgeEvents(edgeId);
- Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RULE_CHAIN.equals(ee.getType())));
- Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.DEVICE.equals(ee.getType())));
- Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.ASSET.equals(ee.getType())));
- Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RELATION.equals(ee.getType())));
}
@Test
@@ -195,7 +185,7 @@ public class EdgeEventControllerTest extends AbstractControllerTest {
edgeEvent.setCreatedTime(System.currentTimeMillis());
edgeEvent.setTenantId(tenantId);
edgeEvent.setAction(EdgeEventActionType.ADDED);
- edgeEvent.setEntityId(tenantAdmin.getUuidId());
+ edgeEvent.setEntityId(tenantAdminUser.getUuidId());
edgeEvent.setType(EdgeEventType.ALARM);
try {
edgeEventDao.saveAsync(edgeEvent).get();
diff --git a/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java
index a65769f3f1..beabcf77d1 100644
--- a/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java
@@ -43,6 +43,7 @@ import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer;
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.EntityViewInfo;
import org.thingsboard.server.common.data.StringUtils;
@@ -170,7 +171,7 @@ public class EntityViewControllerTest extends AbstractControllerTest {
testBroadcastEntityStateChangeEventTime(foundEntityView.getId(), tenantId, 1);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundEntityView, foundEntityView,
tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.ADDED, ActionType.ADDED, 1, 0, 1);
+ ActionType.ADDED, 1, 1, 1);
Mockito.reset(tbClusterService, auditLogService);
savedView.setName("New test entity view");
@@ -183,7 +184,7 @@ public class EntityViewControllerTest extends AbstractControllerTest {
testBroadcastEntityStateChangeEventTime(foundEntityView.getId(), tenantId, 1);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundEntityView, foundEntityView,
tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.UPDATED, ActionType.UPDATED, 1, 1, 5);
+ ActionType.UPDATED, 1, 1, 5);
doGet("/api/tenant/entityViews?entityViewName=" + name)
.andExpect(status().isNotFound())
@@ -247,13 +248,13 @@ public class EntityViewControllerTest extends AbstractControllerTest {
doDelete("/api/entityView/" + entityIdStr)
.andExpect(status().isOk());
- testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedView, savedView.getId(), savedView.getId(),
+ testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedView, savedView.getId(), savedView.getId(),
tenantId, view.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
ActionType.DELETED, entityIdStr);
doGet("/api/entityView/" + entityIdStr)
.andExpect(status().isNotFound())
- .andExpect(statusReason(containsString(msgErrorNoFound("Entity view",entityIdStr))));
+ .andExpect(statusReason(containsString(msgErrorNoFound(EntityType.ENTITY_VIEW.getNormalName(), entityIdStr))));
}
@Test
@@ -286,7 +287,7 @@ public class EntityViewControllerTest extends AbstractControllerTest {
testBroadcastEntityStateChangeEventTime(savedView.getId(), tenantId, 1);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(savedView, savedView,
tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.UPDATED, ActionType.UPDATED, 1, 1, 5);
+ ActionType.UPDATED, 1, 1, 5);
Mockito.reset(tbClusterService, auditLogService);
EntityView assignedView = doPost(
@@ -298,9 +299,9 @@ public class EntityViewControllerTest extends AbstractControllerTest {
assertEquals(savedCustomer.getId(), foundView.getCustomerId());
testBroadcastEntityStateChangeEventNever(foundView.getId());
- testNotifyEntityAllOneTime(foundView, foundView.getId(), foundView.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(foundView, foundView.getId(), foundView.getId(),
tenantId, foundView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.ASSIGNED_TO_CUSTOMER,
+ ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED,
foundView.getId().getId().toString(), foundView.getCustomerId().getId().toString(), savedCustomer.getTitle());
EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class);
@@ -310,9 +311,9 @@ public class EntityViewControllerTest extends AbstractControllerTest {
assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId());
testBroadcastEntityStateChangeEventNever(foundView.getId());
- testNotifyEntityAllOneTime(unAssignedView, savedView.getId(), savedView.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(unAssignedView, savedView.getId(), savedView.getId(),
tenantId, savedView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.UNASSIGNED_FROM_CUSTOMER,
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED,
assignedView.getId().getId().toString(), savedView.getCustomerId().getId().toString(), savedCustomer.getTitle());
}
@@ -328,9 +329,9 @@ public class EntityViewControllerTest extends AbstractControllerTest {
Assert.assertTrue(publicCustomer.isPublic());
testBroadcastEntityStateChangeEventNever(assignedView.getId());
- testNotifyEntityAllOneTime(assignedView, assignedView.getId(), assignedView.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(assignedView, assignedView.getId(), assignedView.getId(),
tenantId, assignedView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.ASSIGNED_TO_CUSTOMER,
+ ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED,
assignedView.getId().getId().toString(), assignedView.getCustomerId().getId().toString(), publicCustomer.getTitle());
EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class);
@@ -343,9 +344,9 @@ public class EntityViewControllerTest extends AbstractControllerTest {
assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId());
testBroadcastEntityStateChangeEventNever(foundView.getId());
- testNotifyEntityAllOneTime(unAssignedView, unAssignedView.getId(), unAssignedView.getId(),
+ testNotifyAssignUnassignEntityAllOneTime(unAssignedView, unAssignedView.getId(), unAssignedView.getId(),
tenantId, publicCustomer.getId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.UNASSIGNED_FROM_CUSTOMER,
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED,
unAssignedView.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle());
}
@@ -425,11 +426,11 @@ public class EntityViewControllerTest extends AbstractControllerTest {
testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(),
tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity*2, 0);
+ ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity * 2, 0);
testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(),
tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity,
+ ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, cntEntity, cntEntity,
cntEntity*2, 3);
}
@@ -464,7 +465,7 @@ public class EntityViewControllerTest extends AbstractControllerTest {
testBroadcastEntityStateChangeEventNever(loadedNamesOfView1.get(0).getId());
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new EntityView(), new EntityView(),
tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
- ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3);
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, cntEntity, cntEntity, 3);
PageData pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF,
new PageLink(4, 0, name1));
diff --git a/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java
index f4472e83be..3ebbb9ebbc 100644
--- a/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java
@@ -339,7 +339,7 @@ public class OtaPackageControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new OtaPackageInfo(), new OtaPackageInfo(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, ActionType.ADDED, cntEntity, 0, (cntEntity*2 - startIndexSaveData));
+ ActionType.ADDED, cntEntity, 0, (cntEntity*2 - startIndexSaveData));
List loadedFirmwares = new ArrayList<>();
PageLink pageLink = new PageLink(24);
diff --git a/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java
index 59a305fe5a..cafeabcf16 100644
--- a/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java
@@ -21,7 +21,6 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import org.junit.jupiter.api.Assertions;
import org.mockito.AdditionalAnswers;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,7 +30,6 @@ import org.springframework.test.context.ContextConfiguration;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.action.TbCreateAlarmNode;
import org.thingsboard.rule.engine.action.TbCreateAlarmNodeConfiguration;
-import org.thingsboard.rule.engine.api.TbVersionedNode;
import org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode;
import org.thingsboard.rule.engine.metadata.TbGetRelatedDataNodeConfiguration;
import org.thingsboard.server.common.data.StringUtils;
@@ -52,7 +50,6 @@ import org.thingsboard.server.dao.rule.RuleChainDao;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -63,7 +60,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@DaoSqlTest
public class RuleChainControllerTest extends AbstractControllerTest {
- private IdComparator idComparator = new IdComparator<>();
+ private final IdComparator idComparator = new IdComparator<>();
private Tenant savedTenant;
private User tenantAdmin;
@@ -245,7 +242,7 @@ public class RuleChainControllerTest extends AbstractControllerTest {
doDelete("/api/ruleChain/" + savedRuleChain.getId().getId().toString())
.andExpect(status().isOk());
- testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedRuleChain, savedRuleChain.getId(), savedRuleChain.getId(),
+ testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedRuleChain, savedRuleChain.getId(), savedRuleChain.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, savedRuleChain.getId().getId().toString());
@@ -260,14 +257,13 @@ public class RuleChainControllerTest extends AbstractControllerTest {
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
- List edgeRuleChains = new ArrayList<>();
PageLink pageLink = new PageLink(17);
PageData pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/ruleChains?",
new TypeReference<>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
- edgeRuleChains.addAll(pageData.getData());
+ List edgeRuleChains = new ArrayList<>(pageData.getData());
Mockito.reset(tbClusterService, auditLogService);
@@ -284,11 +280,7 @@ public class RuleChainControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new RuleChain(), new RuleChain(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity * 2);
- testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new RuleChain(), new RuleChain(),
- savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
- ActionType.ASSIGNED_TO_EDGE, ActionType.ASSIGNED_TO_EDGE, cntEntity, cntEntity, cntEntity * 2,
- new String(), new String(), new String());
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity * 2);
Mockito.reset(tbClusterService, auditLogService);
List loadedEdgeRuleChains = new ArrayList<>();
@@ -303,8 +295,8 @@ public class RuleChainControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(edgeRuleChains, idComparator);
- Collections.sort(loadedEdgeRuleChains, idComparator);
+ edgeRuleChains.sort(idComparator);
+ loadedEdgeRuleChains.sort(idComparator);
Assert.assertEquals(edgeRuleChains, loadedEdgeRuleChains);
diff --git a/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java
index 47cac1b549..f7e5f6f6f3 100644
--- a/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java
@@ -15,16 +15,28 @@
*/
package org.thingsboard.server.controller;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Assert;
import org.junit.Test;
+import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
+import org.thingsboard.server.common.data.query.EntityKey;
+import org.thingsboard.server.common.data.query.SingleEntityFilter;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.service.DaoSqlTest;
+import java.util.List;
+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.thingsboard.server.common.data.query.EntityKeyType.TIME_SERIES;
@DaoSqlTest
+@TestPropertySource(properties = {
+ "sql.attributes.value_no_xss_validation=true",
+ "sql.ts.value_no_xss_validation=true"
+})
public class TelemetryControllerTest extends AbstractControllerTest {
@Test
@@ -39,6 +51,104 @@ public class TelemetryControllerTest extends AbstractControllerTest {
doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest());
}
+ @Test
+ public void testDeleteAllTelemetryWithLatest() throws Exception {
+ loginTenantAdmin();
+ Device device = createDevice();
+
+ SingleEntityFilter filter = new SingleEntityFilter();
+ filter.setSingleEntity(device.getId());
+
+ getWsClient().subscribeLatestUpdate(List.of(new EntityKey(TIME_SERIES, "data")), filter);
+
+ getWsClient().registerWaitForUpdate(1);
+
+ long startTs = System.currentTimeMillis();
+
+ String testBody = "{\"data\": \"value\"}";
+ doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", testBody, String.class, status().isOk());
+
+ long endTs = System.currentTimeMillis();
+
+ ObjectNode latest = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data", ObjectNode.class);
+
+ Assert.assertNotNull(latest);
+ var data = latest.get("data");
+ Assert.assertNotNull(data);
+
+ Assert.assertEquals("value", data.get(0).get("value").asText());
+
+ ObjectNode timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data&startTs={startTs}&endTs={endTs}", ObjectNode.class, startTs, endTs);
+
+ Assert.assertNotNull(timeseries);
+
+ Assert.assertEquals("value", timeseries.get("data").get(0).get("value").asText());
+
+ doDeleteAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/delete?keys=data&deleteAllDataForKeys=true", String.class);
+
+ latest = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data", ObjectNode.class);
+
+ Assert.assertTrue(latest.get("data").get(0).get("value").isNull());
+
+ timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data&startTs={startTs}&endTs={endTs}", ObjectNode.class, startTs, endTs);
+
+ Assert.assertTrue(timeseries.isEmpty());
+ }
+
+ @Test
+ public void testDeleteAllTelemetryWithoutLatest() throws Exception {
+ loginTenantAdmin();
+ Device device = createDevice();
+
+ SingleEntityFilter filter = new SingleEntityFilter();
+ filter.setSingleEntity(device.getId());
+
+ getWsClient().subscribeLatestUpdate(List.of(new EntityKey(TIME_SERIES, "data")), filter);
+
+ getWsClient().registerWaitForUpdate(1);
+
+ long startTs = System.currentTimeMillis();
+
+ String testBody = "{\"data\": \"value\"}";
+ doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", testBody, String.class, status().isOk());
+
+ long endTs = System.currentTimeMillis();
+
+ ObjectNode latest = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data", ObjectNode.class);
+
+ Assert.assertNotNull(latest);
+
+ Assert.assertEquals("value", latest.get("data").get(0).get("value").asText());
+
+ ObjectNode timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data&startTs={startTs}&endTs={endTs}", ObjectNode.class, startTs, endTs);
+
+ Assert.assertNotNull(timeseries);
+
+ Assert.assertEquals("value", timeseries.get("data").get(0).get("value").asText());
+
+ doDeleteAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/delete?keys=data&deleteAllDataForKeys=true&deleteLatest=false", String.class);
+
+ latest = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data", ObjectNode.class);
+
+ Assert.assertEquals("value", latest.get("data").get(0).get("value").asText());
+
+ timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data&startTs={startTs}&endTs={endTs}", ObjectNode.class, startTs, endTs);
+
+ Assert.assertTrue(timeseries.isEmpty());
+ }
+
+ @Test
+ public void testValueConstraintValidator() throws Exception {
+ loginTenantAdmin();
+ Device device = createDevice();
+ String correctRequestBody = "{\"data\": \"value\"}";
+ doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", correctRequestBody, String.class, status().isOk());
+ doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", correctRequestBody, String.class, status().isOk());
+ String invalidRequestBody = "{\"data\": \"alert(document)\\\"> \"}";
+ doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", invalidRequestBody, String.class, status().isBadRequest());
+ doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest());
+ }
+
private Device createDevice() throws Exception {
String testToken = "TEST_TOKEN";
diff --git a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
index 67564ec898..28bb987257 100644
--- a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
@@ -113,7 +113,7 @@ public class UserControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundUser, foundUser,
SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL,
- ActionType.ADDED, ActionType.ADDED, 1, 1, 1);
+ ActionType.ADDED, 1, 1, 1);
Mockito.reset(tbClusterService, auditLogService);
resetTokens();
@@ -152,7 +152,7 @@ public class UserControllerTest extends AbstractControllerTest {
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(foundUser, foundUser.getId(), foundUser.getId(),
SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL,
- ActionType.DELETED, SYSTEM_TENANT.getId().toString());
+ ActionType.DELETED, ActionType.DELETED, SYSTEM_TENANT.getId().toString());
}
@Test
@@ -397,7 +397,7 @@ public class UserControllerTest extends AbstractControllerTest {
testManyUser.setTenantId(tenantId);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(testManyUser, testManyUser,
SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL,
- ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity);
+ ActionType.ADDED, cntEntity, cntEntity, cntEntity);
List loadedTenantAdmins = new ArrayList<>();
PageLink pageLink = new PageLink(33);
@@ -510,7 +510,7 @@ public class UserControllerTest extends AbstractControllerTest {
testManyUser.setTenantId(tenantId);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(testManyUser, testManyUser,
SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL,
- ActionType.DELETED, ActionType.DELETED, cntEntity, NUMBER_OF_USERS, cntEntity, new String());
+ ActionType.DELETED, cntEntity, NUMBER_OF_USERS, cntEntity, "");
pageLink = new PageLink(4, 0, email1);
pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?",
diff --git a/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java b/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java
new file mode 100644
index 0000000000..0394e8a505
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java
@@ -0,0 +1,160 @@
+/**
+ * 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.controller.plugin;
+
+import lombok.extern.slf4j.Slf4j;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.adapter.NativeWebSocketSession;
+import org.thingsboard.common.util.ThingsBoardThreadFactory;
+import org.thingsboard.server.service.ws.WebSocketSessionRef;
+
+import javax.websocket.RemoteEndpoint;
+import javax.websocket.SendHandler;
+import javax.websocket.SendResult;
+import javax.websocket.Session;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.BDDMockito.willAnswer;
+import static org.mockito.BDDMockito.willDoNothing;
+import static org.mockito.BDDMockito.willReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+@Slf4j
+class TbWebSocketHandlerTest {
+
+ TbWebSocketHandler wsHandler;
+ NativeWebSocketSession session;
+ Session nativeSession;
+ RemoteEndpoint.Async asyncRemote;
+ WebSocketSessionRef sessionRef;
+ int maxMsgQueuePerSession;
+ TbWebSocketHandler.SessionMetaData sendHandler;
+ ExecutorService executor;
+
+ @BeforeEach
+ void setUp() throws IOException {
+ maxMsgQueuePerSession = 100;
+ executor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName(getClass().getSimpleName()));
+ wsHandler = spy(new TbWebSocketHandler());
+ willDoNothing().given(wsHandler).close(any(), any());
+ session = mock(NativeWebSocketSession.class);
+ nativeSession = mock(Session.class);
+ willReturn(nativeSession).given(session).getNativeSession(Session.class);
+ asyncRemote = mock(RemoteEndpoint.Async.class);
+ willReturn(asyncRemote).given(nativeSession).getAsyncRemote();
+ sessionRef = mock(WebSocketSessionRef.class, Mockito.RETURNS_DEEP_STUBS); //prevent NPE on logs
+ sendHandler = spy(wsHandler.new SessionMetaData(session, sessionRef, maxMsgQueuePerSession));
+ }
+
+ @AfterEach
+ void tearDown() {
+ if (executor != null) {
+ executor.shutdownNow();
+ }
+ }
+
+ @Test
+ void sendHandler_sendMsg_parallel_no_race() throws InterruptedException {
+ CountDownLatch finishLatch = new CountDownLatch(maxMsgQueuePerSession * 2);
+ AtomicInteger sendersCount = new AtomicInteger();
+ willAnswer(invocation -> {
+ assertThat(sendersCount.incrementAndGet()).as("no race").isEqualTo(1);
+ String text = invocation.getArgument(0);
+ SendHandler onResultHandler = invocation.getArgument(1);
+ SendResult sendResult = new SendResult();
+ executor.submit(() -> {
+ sendersCount.decrementAndGet();
+ onResultHandler.onResult(sendResult);
+ finishLatch.countDown();
+ });
+ return null;
+ }).given(asyncRemote).sendText(anyString(), any());
+
+ assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse();
+ //first batch
+ IntStream.range(0, maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i));
+ Awaitility.await("first batch processed").atMost(30, TimeUnit.SECONDS).until(() -> finishLatch.getCount() == maxMsgQueuePerSession);
+ assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse();
+ //second batch - to test pause between big msg batches
+ IntStream.range(100, 100 + maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i));
+ assertThat(finishLatch.await(30, TimeUnit.SECONDS)).as("all callbacks fired").isTrue();
+
+ verify(sendHandler, never()).closeSession(any());
+ verify(sendHandler, times(maxMsgQueuePerSession * 2)).onResult(any());
+ assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse();
+ }
+
+ @Test
+ void sendHandler_sendMsg_message_order() throws InterruptedException {
+ CountDownLatch finishLatch = new CountDownLatch(maxMsgQueuePerSession);
+ Collection outputs = new ConcurrentLinkedQueue<>();
+ willAnswer(invocation -> {
+ String text = invocation.getArgument(0);
+ outputs.add(text);
+ SendHandler onResultHandler = invocation.getArgument(1);
+ SendResult sendResult = new SendResult();
+ executor.submit(() -> {
+ onResultHandler.onResult(sendResult);
+ finishLatch.countDown();
+ });
+ return null;
+ }).given(asyncRemote).sendText(anyString(), any());
+
+ List inputs = IntStream.range(0, maxMsgQueuePerSession).mapToObj(i -> "msg " + i).collect(Collectors.toList());
+ inputs.forEach(s -> sendHandler.sendMsg(s));
+
+ assertThat(finishLatch.await(30, TimeUnit.SECONDS)).as("all callbacks fired").isTrue();
+ assertThat(outputs).as("inputs exactly the same as outputs").containsExactlyElementsOf(inputs);
+
+ verify(sendHandler, never()).closeSession(any());
+ verify(sendHandler, times(maxMsgQueuePerSession)).onResult(any());
+ }
+
+ @Test
+ void sendHandler_sendMsg_queue_size_exceed() {
+ willDoNothing().given(asyncRemote).sendText(anyString(), any()); // send text will never call back, so queue will grow each sendMsg
+ sendHandler.sendMsg("first message to stay in-flight all the time during this test");
+ IntStream.range(0, maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i));
+ verify(sendHandler, never()).closeSession(any());
+ sendHandler.sendMsg("excessive message");
+ verify(sendHandler, times(1)).closeSession(eq(new CloseStatus(1008, "Max pending updates limit reached!")));
+ verify(asyncRemote, times(1)).sendText(anyString(), any());
+ }
+
+}
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 82b2ce3ec2..32f5aa109b 100644
--- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java
@@ -36,7 +36,6 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.StringUtils;
-import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.asset.Asset;
@@ -70,7 +69,6 @@ import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType;
-import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.edge.imitator.EdgeImitator;
@@ -85,6 +83,7 @@ import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UplinkMsg;
import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
@@ -100,16 +99,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@TestPropertySource(properties = {
"edges.enabled=true",
- "queue.rule-engine.stats.enabled=false",
+ "queue.rule-engine.stats.enabled=false"
})
abstract public class AbstractEdgeTest extends AbstractControllerTest {
private static final String THERMOSTAT_DEVICE_PROFILE_NAME = "Thermostat";
- protected Tenant savedTenant;
- protected TenantId tenantId;
- protected User tenantAdmin;
-
protected DeviceProfile thermostatDeviceProfile;
protected EdgeImitator edgeImitator;
@@ -125,27 +120,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
protected TbClusterService clusterService;
@Before
- public void beforeTest() throws Exception {
- loginSysAdmin();
-
- Tenant tenant = new Tenant();
- tenant.setTitle("My tenant");
- savedTenant = doPost("/api/tenant", tenant, Tenant.class);
- tenantId = savedTenant.getId();
- Assert.assertNotNull(savedTenant);
-
- tenantAdmin = new User();
- tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
- tenantAdmin.setTenantId(savedTenant.getId());
- tenantAdmin.setEmail("tenant2@thingsboard.org");
- tenantAdmin.setFirstName("Joe");
- tenantAdmin.setLastName("Downs");
-
- tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
- // sleep 0.5 second to avoid CREDENTIALS updated message for the user
- // user credentials is going to be stored and updated event pushed to edge notification service
- // while service will be processing this event edge could be already added and additional message will be pushed
- Thread.sleep(500);
+ public void setupEdgeTest() throws Exception {
+ loginTenantAdmin();
installation();
@@ -181,31 +157,32 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
}
@After
- public void afterTest() throws Exception {
+ public void teardownEdgeTest() {
try {
- edgeImitator.disconnect();
- } catch (Exception ignored){}
-
- loginSysAdmin();
+ edgeImitator.expectMessageAmount(2);
+ loginTenantAdmin();
+ Assert.assertTrue(edgeImitator.waitForMessages());
- doDelete("/api/tenant/" + savedTenant.getUuidId())
- .andExpect(status().isOk());
+ doDelete("/api/edge/" + edge.getId().toString())
+ .andExpect(status().isOk());
+ edgeImitator.disconnect();
+ } catch (Exception ignored) {}
}
private void installation() {
- edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class);
-
thermostatDeviceProfile = this.createDeviceProfile(THERMOSTAT_DEVICE_PROFILE_NAME,
createMqttDeviceProfileTransportConfiguration(new JsonTransportPayloadConfiguration(), false));
-
extendDeviceProfileData(thermostatDeviceProfile);
thermostatDeviceProfile = doPost("/api/deviceProfile", thermostatDeviceProfile, DeviceProfile.class);
Device savedDevice = saveDevice("Edge Device 1", THERMOSTAT_DEVICE_PROFILE_NAME);
- doPost("/api/edge/" + edge.getUuidId()
- + "/device/" + savedDevice.getUuidId(), Device.class);
Asset savedAsset = saveAsset("Edge Asset 1");
+
+ edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class);
+
+ doPost("/api/edge/" + edge.getUuidId()
+ + "/device/" + savedDevice.getUuidId(), Device.class);
doPost("/api/edge/" + edge.getUuidId()
+ "/asset/" + savedAsset.getUuidId(), Asset.class);
}
@@ -244,18 +221,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
validateEdgeConfiguration();
- // 5 messages
- // - 2 from device profile fetcher (default and thermostat)
- // - 1 from device fetcher
- // - 1 from device profile controller (thermostat)
- // - 1 from device controller (thermostat)
- validateDeviceProfiles();
-
- // 2 messages - 1 from device fetcher and 1 from device controller
- validateDevices();
-
- // 2 messages - 1 from asset fetcher and 1 from asset controller
- validateAssets();
+ // 1 message from queue fetcher
+ validateQueues();
// 2 messages - 1 from rule chain fetcher and 1 from rule chain controller
UUID ruleChainUUID = validateRuleChains();
@@ -266,20 +233,32 @@ 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
+ // - 2 from device profile fetcher (default and thermostat)
+ // - 1 from device fetcher
+ // - 1 from device controller (thermostat)
+ validateDeviceProfiles();
+
// 3 messages
// - 1 message from asset profile fetcher
// - 1 message from asset fetcher
// - 1 message from asset controller
validateAssetProfiles();
- // 1 message from queue fetcher
- validateQueues();
+ // 2 messages - 1 from device fetcher and 1 from device controller
+ validateDevices();
- // 1 message from user fetcher
- validateUsers();
+ // 2 messages - 1 from asset fetcher and 1 from asset controller
+ validateAssets();
// 1 message from public customer fetcher
validatePublicCustomer();
+
+ // 1 message from user fetcher
+ validateUsers();
+
+ // 1 message sync completed
+ validateSyncCompleted();
}
private void validateEdgeConfiguration() throws Exception {
@@ -290,12 +269,11 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
private void validateDeviceProfiles() throws Exception {
List deviceProfileUpdateMsgList = edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class);
- // default msg
- // thermostat msg from fetcher
+ // default msg device profile from fetcher
+ // thermostat msg from device profile fetcher
// thermostat msg from device fetcher
- // thermostat msg from controller
// thermostat msg from creation of device
- Assert.assertEquals(5, deviceProfileUpdateMsgList.size());
+ Assert.assertEquals(4, deviceProfileUpdateMsgList.size());
Optional thermostatProfileUpdateMsgOpt =
deviceProfileUpdateMsgList.stream().filter(dfum -> THERMOSTAT_DEVICE_PROFILE_NAME.equals(dfum.getName())).findAny();
Assert.assertTrue(thermostatProfileUpdateMsgOpt.isPresent());
@@ -394,7 +372,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
}
}
- private void validateMailAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) throws JsonProcessingException {
+ private void validateMailAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue());
Assert.assertNotNull(jsonNode.get("mailFrom"));
Assert.assertNotNull(jsonNode.get("smtpProtocol"));
@@ -403,7 +381,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
Assert.assertNotNull(jsonNode.get("timeout"));
}
- private void validateMailTemplatesAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) throws JsonProcessingException {
+ private void validateMailTemplatesAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue());
Assert.assertNotNull(jsonNode.get("accountActivated"));
Assert.assertNotNull(jsonNode.get("accountLockout"));
@@ -449,7 +427,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
UUID userUUID = new UUID(userUpdateMsg.getIdMSB(), userUpdateMsg.getIdLSB());
User user = doGet("/api/user/" + userUUID, User.class);
Assert.assertNotNull(user);
- Assert.assertEquals("tenant2@thingsboard.org", userUpdateMsg.getEmail());
+ Assert.assertEquals("testtenant@thingsboard.org", userUpdateMsg.getEmail());
testAutoGeneratedCodeByProtobuf(userUpdateMsg);
}
@@ -464,6 +442,11 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
Assert.assertTrue(customer.isPublic());
}
+ private void validateSyncCompleted() {
+ Optional syncCompletedMsgOpt = edgeImitator.findMessageByType(SyncCompletedMsg.class);
+ Assert.assertTrue(syncCompletedMsgOpt.isPresent());
+ }
+
protected Device saveDeviceOnCloudAndVerifyDeliveryToEdge() throws Exception {
// create device and assign to edge
Device savedDevice = saveDevice(StringUtils.randomAlphanumeric(15), thermostatDeviceProfile.getName());
diff --git a/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java
index 2f5848ece6..e8639e0db7 100644
--- a/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java
@@ -82,11 +82,11 @@ public class AssetEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedAsset.getUuidId().getMostSignificantBits(), assetUpdateMsg.getIdMSB());
Assert.assertEquals(savedAsset.getUuidId().getLeastSignificantBits(), assetUpdateMsg.getIdLSB());
- // delete asset - no messages expected
+ // delete asset - message expected, it was sent to all edges
edgeImitator.expectMessageAmount(1);
doDelete("/api/asset/" + savedAsset.getUuidId())
.andExpect(status().isOk());
- Assert.assertFalse(edgeImitator.waitForMessages(1));
+ Assert.assertTrue(edgeImitator.waitForMessages(1));
// create asset #2 and assign to edge
edgeImitator.expectMessageAmount(2);
@@ -94,7 +94,6 @@ public class AssetEdgeTest extends AbstractEdgeTest {
doPost("/api/edge/" + edge.getUuidId()
+ "/asset/" + savedAsset.getUuidId(), Asset.class);
Assert.assertTrue(edgeImitator.waitForMessages());
- latestMessage = edgeImitator.getLatestMessage();
assetUpdateMsgOpt = edgeImitator.findMessageByType(AssetUpdateMsg.class);
Assert.assertTrue(assetUpdateMsgOpt.isPresent());
assetUpdateMsg = assetUpdateMsgOpt.get();
diff --git a/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java
index b9bf41fde6..251b4b4caf 100644
--- a/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java
@@ -20,12 +20,15 @@ import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EdgeConfiguration;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import java.util.Optional;
+import java.util.UUID;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -74,13 +77,19 @@ public class CustomerEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedCustomer.getTitle(), customerUpdateMsg.getTitle());
// delete customer
- edgeImitator.expectMessageAmount(1);
+ edgeImitator.expectMessageAmount(2);
doDelete("/api/customer/" + savedCustomer.getUuidId())
.andExpect(status().isOk());
Assert.assertTrue(edgeImitator.waitForMessages());
- latestMessage = edgeImitator.getLatestMessage();
- Assert.assertTrue(latestMessage instanceof CustomerUpdateMsg);
- customerUpdateMsg = (CustomerUpdateMsg) latestMessage;
+ edgeConfigurationOpt = edgeImitator.findMessageByType(EdgeConfiguration.class);
+ Assert.assertTrue(edgeConfigurationOpt.isPresent());
+ edgeConfiguration = edgeConfigurationOpt.get();
+ Assert.assertEquals(
+ new CustomerId(EntityId.NULL_UUID),
+ new CustomerId(new UUID(edgeConfiguration.getCustomerIdMSB(), edgeConfiguration.getCustomerIdLSB())));
+ customerUpdateOpt = edgeImitator.findMessageByType(CustomerUpdateMsg.class);
+ Assert.assertTrue(customerUpdateOpt.isPresent());
+ customerUpdateMsg = customerUpdateOpt.get();
Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, customerUpdateMsg.getMsgType());
Assert.assertEquals(customerUpdateMsg.getIdMSB(), savedCustomer.getUuidId().getMostSignificantBits());
Assert.assertEquals(customerUpdateMsg.getIdLSB(), savedCustomer.getUuidId().getLeastSignificantBits());
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 988d6fdc98..94743c4a6b 100644
--- a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java
@@ -77,11 +77,11 @@ public class DashboardEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedDashboard.getUuidId().getMostSignificantBits(), dashboardUpdateMsg.getIdMSB());
Assert.assertEquals(savedDashboard.getUuidId().getLeastSignificantBits(), dashboardUpdateMsg.getIdLSB());
- // delete dashboard - no messages expected
+ // delete dashboard - message expected, it was sent to all edges
edgeImitator.expectMessageAmount(1);
doDelete("/api/dashboard/" + savedDashboard.getUuidId())
.andExpect(status().isOk());
- Assert.assertFalse(edgeImitator.waitForMessages(1));
+ Assert.assertTrue(edgeImitator.waitForMessages(1));
// create dashboard #2 and assign to edge
edgeImitator.expectMessageAmount(1);
diff --git a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java
index 15d5b5c809..1c9a6359d6 100644
--- a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java
@@ -83,6 +83,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@DaoSqlTest
public class DeviceEdgeTest extends AbstractEdgeTest {
+ private static final String DEFAULT_DEVICE_TYPE = "default";
+
@Test
public void testDevices() throws Exception {
// create device and assign to edge; update device
@@ -100,15 +102,15 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedDevice.getUuidId().getMostSignificantBits(), deviceUpdateMsg.getIdMSB());
Assert.assertEquals(savedDevice.getUuidId().getLeastSignificantBits(), deviceUpdateMsg.getIdLSB());
- // delete device - no messages expected
+ // delete device - message expected, message send to all edges
edgeImitator.expectMessageAmount(1);
doDelete("/api/device/" + savedDevice.getUuidId())
.andExpect(status().isOk());
- Assert.assertFalse(edgeImitator.waitForMessages(1));
+ Assert.assertTrue(edgeImitator.waitForMessages(1));
// create device #2 and assign to edge
edgeImitator.expectMessageAmount(2);
- savedDevice = saveDevice("Edge Device 3", "Default");
+ savedDevice = saveDevice("Edge Device 3", DEFAULT_DEVICE_TYPE);
doPost("/api/edge/" + edge.getUuidId()
+ "/device/" + savedDevice.getUuidId(), Device.class);
Assert.assertTrue(edgeImitator.waitForMessages());
@@ -265,14 +267,16 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
public void testDeviceReachedMaximumAllowedOnCloud() throws Exception {
// update tenant profile configuration
loginSysAdmin();
- TenantProfile tenantProfile = doGet("/api/tenantProfile/" + savedTenant.getTenantProfileId().getId(), TenantProfile.class);
+ TenantProfile tenantProfile = doGet("/api/tenantProfile/" + tenantProfileId.getId(), TenantProfile.class);
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration();
profileConfiguration.setMaxDevices(1);
tenantProfile.getProfileData().setConfiguration(profileConfiguration);
doPost("/api/tenantProfile/", tenantProfile, TenantProfile.class);
+ edgeImitator.expectMessageAmount(2);
loginTenantAdmin();
+ Assert.assertTrue(edgeImitator.waitForMessages());
UUID uuid = Uuids.timeBased();
@@ -281,7 +285,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
deviceUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
deviceUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
deviceUpdateMsgBuilder.setName("Edge Device");
- deviceUpdateMsgBuilder.setType("default");
+ deviceUpdateMsgBuilder.setType(DEFAULT_DEVICE_TYPE);
deviceUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build());
@@ -479,7 +483,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
@Test
public void testSendDeviceToCloudWithNameThatAlreadyExistsOnCloud() throws Exception {
String deviceOnCloudName = StringUtils.randomAlphanumeric(15);
- Device deviceOnCloud = saveDevice(deviceOnCloudName, "Default");
+ Device deviceOnCloud = saveDevice(deviceOnCloudName, DEFAULT_DEVICE_TYPE);
UUID uuid = Uuids.timeBased();
diff --git a/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java
index 234a9473fa..75386dbb17 100644
--- a/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java
@@ -94,11 +94,11 @@ public class EntityViewEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(entityViewUpdateMsg.getIdMSB(), savedEntityView.getUuidId().getMostSignificantBits());
Assert.assertEquals(entityViewUpdateMsg.getIdLSB(), savedEntityView.getUuidId().getLeastSignificantBits());
- // delete entity view - no messages expected
+ // delete entity view - message expected, it was sent to all edges
edgeImitator.expectMessageAmount(1);
doDelete("/api/entityView/" + savedEntityView.getUuidId())
.andExpect(status().isOk());
- Assert.assertFalse(edgeImitator.waitForMessages(1));
+ Assert.assertTrue(edgeImitator.waitForMessages(1));
// create entity view #2 and assign to edge
edgeImitator.expectMessageAmount(1);
diff --git a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java
index b810810225..83b2370cf0 100644
--- a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java
@@ -19,6 +19,9 @@ import com.google.protobuf.AbstractMessage;
import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
+import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
+import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.rule.RuleChain;
@@ -33,6 +36,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UplinkMsg;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -81,7 +85,7 @@ public class RuleChainEdgeTest extends AbstractEdgeTest {
edgeImitator.expectMessageAmount(1);
doDelete("/api/ruleChain/" + savedRuleChain.getUuidId())
.andExpect(status().isOk());
- Assert.assertFalse(edgeImitator.waitForMessages(1));
+ Assert.assertTrue(edgeImitator.waitForMessages(5));
}
@Test
@@ -136,24 +140,30 @@ public class RuleChainEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(ruleChainId, receivedRuleChainId);
}
- private void createRuleChainMetadata(RuleChain ruleChain) throws Exception {
+ private void createRuleChainMetadata(RuleChain ruleChain) {
RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
ruleChainMetaData.setRuleChainId(ruleChain.getId());
RuleNode ruleNode1 = new RuleNode();
ruleNode1.setName("name1");
- ruleNode1.setType("type1");
- ruleNode1.setConfiguration(JacksonUtil.toJsonNode("\"key1\": \"val1\""));
+ ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
+ ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
+ TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration();
+ configuration.setFetchTo(TbMsgSource.METADATA);
+ configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
+ ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration));
RuleNode ruleNode2 = new RuleNode();
ruleNode2.setName("name2");
- ruleNode2.setType("type2");
- ruleNode2.setConfiguration(JacksonUtil.toJsonNode("\"key2\": \"val2\""));
+ ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
+ ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
+ ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration));
RuleNode ruleNode3 = new RuleNode();
ruleNode3.setName("name3");
- ruleNode3.setType("type3");
- ruleNode3.setConfiguration(JacksonUtil.toJsonNode("\"key3\": \"val3\""));
+ ruleNode3.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
+ ruleNode3.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
+ ruleNode3.setConfiguration(JacksonUtil.valueToTree(configuration));
List ruleNodes = new ArrayList<>();
ruleNodes.add(ruleNode1);
@@ -172,11 +182,12 @@ public class RuleChainEdgeTest extends AbstractEdgeTest {
@Test
public void testSetRootRuleChain() throws Exception {
// create rule chain
- edgeImitator.expectMessageAmount(1);
RuleChain ruleChain = new RuleChain();
ruleChain.setName("Edge New Root Rule Chain");
ruleChain.setType(RuleChainType.EDGE);
RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class);
+
+ edgeImitator.expectMessageAmount(1);
doPost("/api/edge/" + edge.getUuidId()
+ "/ruleChain/" + savedRuleChain.getUuidId(), RuleChain.class);
Assert.assertTrue(edgeImitator.waitForMessages());
@@ -211,6 +222,6 @@ public class RuleChainEdgeTest extends AbstractEdgeTest {
edgeImitator.expectMessageAmount(1);
doDelete("/api/ruleChain/" + savedRuleChain.getUuidId())
.andExpect(status().isOk());
- Assert.assertFalse(edgeImitator.waitForMessages(1));
+ Assert.assertTrue(edgeImitator.waitForMessages(1));
}
}
diff --git a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java
index 0cf1c2d149..2ee267b88c 100644
--- a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java
@@ -215,7 +215,7 @@ public class TelemetryEdgeTest extends AbstractEdgeTest {
@Test
public void testAttributesUpdatedMsg_userEntity() throws Exception {
- testAttributesUpdatedMsg(tenantAdmin.getId());
+ testAttributesUpdatedMsg(tenantAdminUserId);
}
private void testAttributesUpdatedMsg(EntityId entityId) throws Exception {
diff --git a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java
index f376f50ac5..d1d555f691 100644
--- a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java
+++ b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java
@@ -45,18 +45,18 @@ public class UserEdgeTest extends AbstractEdgeTest {
@Test
public void testCreateUpdateDeleteTenantUser() throws Exception {
// create user
- edgeImitator.expectMessageAmount(2);
+ edgeImitator.expectMessageAmount(3);
User newTenantAdmin = new User();
newTenantAdmin.setAuthority(Authority.TENANT_ADMIN);
- newTenantAdmin.setTenantId(savedTenant.getId());
+ newTenantAdmin.setTenantId(tenantId);
newTenantAdmin.setEmail("tenantAdmin@thingsboard.org");
newTenantAdmin.setFirstName("Boris");
newTenantAdmin.setLastName("Johnson");
User savedTenantAdmin = createUser(newTenantAdmin, "tenant");
- Assert.assertTrue(edgeImitator.waitForMessages()); // wait 2 messages - user update msg and user credentials update msg
- Optional latestMessageOpt = edgeImitator.findMessageByType(UserUpdateMsg.class);
- Assert.assertTrue(latestMessageOpt.isPresent());
- UserUpdateMsg userUpdateMsg = latestMessageOpt.get();
+ Assert.assertTrue(edgeImitator.waitForMessages()); // wait 3 messages - user update msg and x2 user credentials update msgs
+ Optional userUpdateMsgOpt = edgeImitator.findMessageByType(UserUpdateMsg.class);
+ Assert.assertTrue(userUpdateMsgOpt.isPresent());
+ UserUpdateMsg userUpdateMsg = userUpdateMsgOpt.get();
Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, userUpdateMsg.getMsgType());
Assert.assertEquals(savedTenantAdmin.getUuidId().getMostSignificantBits(), userUpdateMsg.getIdMSB());
Assert.assertEquals(savedTenantAdmin.getUuidId().getLeastSignificantBits(), userUpdateMsg.getIdLSB());
@@ -79,8 +79,11 @@ public class UserEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedTenantAdmin.getLastName(), userUpdateMsg.getLastName());
// update user credentials
- edgeImitator.expectMessageAmount(1);
+ edgeImitator.expectMessageAmount(2);
login(savedTenantAdmin.getEmail(), "tenant");
+ Assert.assertTrue(edgeImitator.waitForMessages());
+
+ edgeImitator.expectMessageAmount(1);
ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest();
changePasswordRequest.setCurrentPassword("tenant");
changePasswordRequest.setNewPassword("newTenant");
@@ -93,9 +96,12 @@ public class UserEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedTenantAdmin.getUuidId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB());
Assert.assertTrue(passwordEncoder.matches(changePasswordRequest.getNewPassword(), userCredentialsUpdateMsg.getPassword()));
+ edgeImitator.expectMessageAmount(2);
+ loginTenantAdmin();
+ Assert.assertTrue(edgeImitator.waitForMessages());
+
// delete user
edgeImitator.expectMessageAmount(1);
- login(tenantAdmin.getEmail(), "testPassword1");
doDelete("/api/user/" + savedTenantAdmin.getUuidId())
.andExpect(status().isOk());
Assert.assertTrue(edgeImitator.waitForMessages());
@@ -123,19 +129,19 @@ public class UserEdgeTest extends AbstractEdgeTest {
Assert.assertTrue(edgeImitator.waitForMessages());
// create user
- edgeImitator.expectMessageAmount(2);
+ edgeImitator.expectMessageAmount(3);
User customerUser = new User();
customerUser.setAuthority(Authority.CUSTOMER_USER);
- customerUser.setTenantId(savedTenant.getId());
+ customerUser.setTenantId(tenantId);
customerUser.setCustomerId(savedCustomer.getId());
customerUser.setEmail("customerUser@thingsboard.org");
customerUser.setFirstName("John");
customerUser.setLastName("Edwards");
User savedCustomerUser = createUser(customerUser, "customer");
- Assert.assertTrue(edgeImitator.waitForMessages()); // wait 2 messages - user update msg and user credentials update msg
- Optional latestMessageOpt = edgeImitator.findMessageByType(UserUpdateMsg.class);
- Assert.assertTrue(latestMessageOpt.isPresent());
- UserUpdateMsg userUpdateMsg = latestMessageOpt.get();
+ Assert.assertTrue(edgeImitator.waitForMessages()); // wait 3 messages - user update msg and x2 user credentials update msgs
+ Optional userUpdateMsgOpt = edgeImitator.findMessageByType(UserUpdateMsg.class);
+ Assert.assertTrue(userUpdateMsgOpt.isPresent());
+ UserUpdateMsg userUpdateMsg = userUpdateMsgOpt.get();
Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, userUpdateMsg.getMsgType());
Assert.assertEquals(savedCustomerUser.getUuidId().getMostSignificantBits(), userUpdateMsg.getIdMSB());
Assert.assertEquals(savedCustomerUser.getUuidId().getLeastSignificantBits(), userUpdateMsg.getIdLSB());
@@ -158,8 +164,11 @@ public class UserEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedCustomerUser.getLastName(), userUpdateMsg.getLastName());
// update user credentials
- edgeImitator.expectMessageAmount(1);
+ edgeImitator.expectMessageAmount(2);
login(savedCustomerUser.getEmail(), "customer");
+ Assert.assertTrue(edgeImitator.waitForMessages());
+
+ edgeImitator.expectMessageAmount(1);
ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest();
changePasswordRequest.setCurrentPassword("customer");
changePasswordRequest.setNewPassword("newCustomer");
@@ -172,9 +181,12 @@ public class UserEdgeTest extends AbstractEdgeTest {
Assert.assertEquals(savedCustomerUser.getUuidId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB());
Assert.assertTrue(passwordEncoder.matches(changePasswordRequest.getNewPassword(), userCredentialsUpdateMsg.getPassword()));
+ edgeImitator.expectMessageAmount(2);
+ loginTenantAdmin();
+ Assert.assertTrue(edgeImitator.waitForMessages());
+
// delete user
edgeImitator.expectMessageAmount(1);
- login(tenantAdmin.getEmail(), "testPassword1");
doDelete("/api/user/" + savedCustomerUser.getUuidId())
.andExpect(status().isOk());
Assert.assertTrue(edgeImitator.waitForMessages());
@@ -191,8 +203,8 @@ public class UserEdgeTest extends AbstractEdgeTest {
public void testSendUserCredentialsRequestToCloud() throws Exception {
UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
UserCredentialsRequestMsg.Builder userCredentialsRequestMsgBuilder = UserCredentialsRequestMsg.newBuilder();
- userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdmin.getId().getId().getMostSignificantBits());
- userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdmin.getId().getId().getLeastSignificantBits());
+ userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdminUserId.getId().getMostSignificantBits());
+ userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdminUserId.getId().getLeastSignificantBits());
testAutoGeneratedCodeByProtobuf(userCredentialsRequestMsgBuilder);
uplinkMsgBuilder.addUserCredentialsRequestMsg(userCredentialsRequestMsgBuilder.build());
@@ -207,16 +219,16 @@ public class UserEdgeTest extends AbstractEdgeTest {
AbstractMessage latestMessage = edgeImitator.getLatestMessage();
Assert.assertTrue(latestMessage instanceof UserCredentialsUpdateMsg);
UserCredentialsUpdateMsg userCredentialsUpdateMsg = (UserCredentialsUpdateMsg) latestMessage;
- Assert.assertEquals(tenantAdmin.getId().getId().getMostSignificantBits(), userCredentialsUpdateMsg.getUserIdMSB());
- Assert.assertEquals(tenantAdmin.getId().getId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB());
+ Assert.assertEquals(tenantAdminUserId.getId().getMostSignificantBits(), userCredentialsUpdateMsg.getUserIdMSB());
+ Assert.assertEquals(tenantAdminUserId.getId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB());
}
@Test
public void sendUserCredentialsRequest() throws Exception {
UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
UserCredentialsRequestMsg.Builder userCredentialsRequestMsgBuilder = UserCredentialsRequestMsg.newBuilder();
- userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdmin.getId().getId().getMostSignificantBits());
- userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdmin.getId().getId().getLeastSignificantBits());
+ userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdminUserId.getId().getMostSignificantBits());
+ userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdminUserId.getId().getLeastSignificantBits());
testAutoGeneratedCodeByProtobuf(userCredentialsRequestMsgBuilder);
uplinkMsgBuilder.addUserCredentialsRequestMsg(userCredentialsRequestMsgBuilder.build());
@@ -231,8 +243,8 @@ public class UserEdgeTest extends AbstractEdgeTest {
AbstractMessage latestMessage = edgeImitator.getLatestMessage();
Assert.assertTrue(latestMessage instanceof UserCredentialsUpdateMsg);
UserCredentialsUpdateMsg userCredentialsUpdateMsg = (UserCredentialsUpdateMsg) latestMessage;
- Assert.assertEquals(userCredentialsUpdateMsg.getUserIdMSB(), tenantAdmin.getId().getId().getMostSignificantBits());
- Assert.assertEquals(userCredentialsUpdateMsg.getUserIdLSB(), tenantAdmin.getId().getId().getLeastSignificantBits());
+ Assert.assertEquals(userCredentialsUpdateMsg.getUserIdMSB(), tenantAdminUserId.getId().getMostSignificantBits());
+ Assert.assertEquals(userCredentialsUpdateMsg.getUserIdLSB(), tenantAdminUserId.getId().getLeastSignificantBits());
testAutoGeneratedCodeByProtobuf(userCredentialsUpdateMsg);
}
diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java
index 0edf070aef..67db3e6b27 100644
--- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java
+++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java
@@ -177,16 +177,16 @@ public class EdgeImitator {
result.add(saveDownlinkMsg(adminSettingsUpdateMsg));
}
}
- if (downlinkMsg.getDeviceUpdateMsgCount() > 0) {
- for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) {
- result.add(saveDownlinkMsg(deviceUpdateMsg));
- }
- }
if (downlinkMsg.getDeviceProfileUpdateMsgCount() > 0) {
for (DeviceProfileUpdateMsg deviceProfileUpdateMsg : downlinkMsg.getDeviceProfileUpdateMsgList()) {
result.add(saveDownlinkMsg(deviceProfileUpdateMsg));
}
}
+ if (downlinkMsg.getDeviceUpdateMsgCount() > 0) {
+ for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) {
+ result.add(saveDownlinkMsg(deviceUpdateMsg));
+ }
+ }
if (downlinkMsg.getDeviceCredentialsUpdateMsgCount() > 0) {
for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg : downlinkMsg.getDeviceCredentialsUpdateMsgList()) {
result.add(saveDownlinkMsg(deviceCredentialsUpdateMsg));
@@ -293,6 +293,9 @@ public class EdgeImitator {
if (downlinkMsg.hasEdgeConfiguration()) {
result.add(saveDownlinkMsg(downlinkMsg.getEdgeConfiguration()));
}
+ if (downlinkMsg.hasSyncCompletedMsg()) {
+ result.add(saveDownlinkMsg(downlinkMsg.getSyncCompletedMsg()));
+ }
return Futures.allAsList(result);
}
diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
index 6c2e5e9c5e..b86287c5d7 100644
--- a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
+++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
@@ -27,7 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.util.ReflectionTestUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
-import org.thingsboard.rule.engine.metadata.FetchTo;
+import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
import org.thingsboard.server.actors.ActorSystemContext;
@@ -39,6 +39,8 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.event.Event;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChain;
@@ -142,7 +144,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode1.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration();
- configuration1.setFetchTo(FetchTo.METADATA);
+ configuration1.setFetchTo(TbMsgSource.METADATA);
configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1"));
ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1));
@@ -152,14 +154,14 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode2.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
- configuration2.setFetchTo(FetchTo.METADATA);
+ configuration2.setFetchTo(TbMsgSource.METADATA);
configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2));
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
- metaData.addConnectionInfo(0, 1, "Success");
+ metaData.addConnectionInfo(0, 1, TbNodeConnectionType.SUCCESS);
metaData = saveRuleChainMetaData(metaData);
Assert.assertNotNull(metaData);
@@ -179,14 +181,14 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
- TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback);
QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
// Pushing Message to the system
actorSystem.tell(qMsg);
Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
PageData eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000);
- List events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
+ List events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
EventInfo inEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get();
@@ -203,7 +205,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
RuleNode lastRuleNode = metaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get();
eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000);
- events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
+ events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
@@ -248,7 +250,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode1.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration();
- configuration1.setFetchTo(FetchTo.METADATA);
+ configuration1.setFetchTo(TbMsgSource.METADATA);
configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1"));
ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1));
@@ -265,7 +267,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
NodeConnectionInfo connection = new NodeConnectionInfo();
connection.setFromIndex(0);
connection.setToIndex(1);
- connection.setType("Success");
+ connection.setType(TbNodeConnectionType.SUCCESS);
rootMetaData.setConnections(Collections.singletonList(connection));
rootMetaData = saveRuleChainMetaData(rootMetaData);
Assert.assertNotNull(rootMetaData);
@@ -282,7 +284,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode2.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
- configuration2.setFetchTo(FetchTo.METADATA);
+ configuration2.setFetchTo(TbMsgSource.METADATA);
configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2));
@@ -304,7 +306,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
- TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback);
QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
// Pushing Message to the system
actorSystem.tell(qMsg);
@@ -312,7 +314,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
PageData eventsPage = getDebugEvents(savedTenant.getId(), rootRuleChain.getFirstRuleNodeId(), 1000);
- List events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
+ List events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
@@ -330,7 +332,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
RuleNode lastRuleNode = secondaryMetaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get();
eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000);
- events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
+ events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
Assert.assertEquals(2, events.size());
diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
index 9753f06aff..9b05be4a05 100644
--- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
+++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
@@ -24,7 +24,7 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
-import org.thingsboard.rule.engine.metadata.FetchTo;
+import org.thingsboard.rule.engine.util.TbMsgSource;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
import org.thingsboard.server.actors.ActorSystemContext;
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.event.EventType;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
@@ -97,7 +98,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
ruleNode.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version());
ruleNode.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration();
- configuration.setFetchTo(FetchTo.METADATA);
+ configuration.setFetchTo(TbMsgSource.METADATA);
configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey"));
ruleNode.setConfiguration(JacksonUtil.valueToTree(configuration));
@@ -139,7 +140,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
log.warn("attr updated");
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);
Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true);
- TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback);
QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(tenantId, tbMsg, null, null);
// Pushing Message to the system
log.warn("before tell tbMsgCallback");
@@ -147,12 +148,12 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
log.warn("awaiting tbMsgCallback");
Mockito.verify(tbMsgCallback, Mockito.timeout(TimeUnit.SECONDS.toMillis(TIMEOUT))).onSuccess();
log.warn("awaiting events");
- List events = Awaitility.await("get debug by custom event")
+ List events = Awaitility.await("get debug by post telemetry event")
.pollInterval(10, MILLISECONDS)
.atMost(TIMEOUT, TimeUnit.SECONDS)
.until(() -> {
List debugEvents = getDebugEvents(tenantId, ruleChainFinal.getFirstRuleNodeId(), 1000)
- .getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList());
+ .getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList());
log.warn("filtered debug events [{}]", debugEvents.size());
debugEvents.forEach((e) -> log.warn("event: {}", e));
return debugEvents;
diff --git a/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java
index f01f4fae04..a88f25d5bf 100644
--- a/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java
@@ -71,8 +71,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-;
-
@Slf4j
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = DeviceProvisionServiceImpl.class)
diff --git a/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java b/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java
index dc3cc84c72..c1f34217ac 100644
--- a/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java
@@ -24,9 +24,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
@@ -45,6 +47,8 @@ import java.util.UUID;
@RunWith(MockitoJUnitRunner.class)
public class RuleChainMsgConstructorTest {
+ private static final String RPC_CONNECTION_TYPE = "RPC";
+
private RuleChainMsgConstructor constructor;
private TenantId tenantId;
@@ -99,19 +103,19 @@ public class RuleChainMsgConstructorTest {
Assert.assertEquals("Connections count incorrect!", 13, ruleChainMetadataUpdateMsg.getConnectionsCount());
Assert.assertEquals("Rule chain connections count incorrect!", 0, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount());
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 6, "Success"), ruleChainMetadataUpdateMsg.getConnections(0));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 10, "Success"), ruleChainMetadataUpdateMsg.getConnections(1));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(2));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(3));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(4));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 11, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(5));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 7, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(6));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 4, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(7));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 5, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(8));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 8, "Other"), ruleChainMetadataUpdateMsg.getConnections(9));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(10));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 11, "Success"), ruleChainMetadataUpdateMsg.getConnections(11));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(10, 9, "RPC"), ruleChainMetadataUpdateMsg.getConnections(12));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 6, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(0));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 10, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(1));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(2));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 11, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(3));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 11, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(4));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 11, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(5));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 7, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(6));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 4, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(7));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 5, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(8));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 8, TbNodeConnectionType.OTHER), ruleChainMetadataUpdateMsg.getConnections(9));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(10));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 11, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(11));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(10, 9, RPC_CONNECTION_TYPE), ruleChainMetadataUpdateMsg.getConnections(12));
}
@Test
@@ -130,20 +134,20 @@ public class RuleChainMsgConstructorTest {
Assert.assertEquals("Connections count incorrect!", 10, ruleChainMetadataUpdateMsg.getConnectionsCount());
Assert.assertEquals("Rule chain connections count incorrect!", 1, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount());
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(2, 5, "Success"), ruleChainMetadataUpdateMsg.getConnections(0));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(1));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(2));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 9, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(3));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 6, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(4));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 3, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(5));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 4, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(6));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 7, "Other"), ruleChainMetadataUpdateMsg.getConnections(7));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 8, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(8));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, "Success"), ruleChainMetadataUpdateMsg.getConnections(9));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(2, 5, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(0));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 9, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(1));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 9, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(2));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 9, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(3));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 6, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(4));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 3, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(5));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 4, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(6));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 7, TbNodeConnectionType.OTHER), ruleChainMetadataUpdateMsg.getConnections(7));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 8, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(8));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 9, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(9));
RuleChainConnectionInfoProto ruleChainConnection = ruleChainMetadataUpdateMsg.getRuleChainConnections(0);
Assert.assertEquals("From index incorrect!", 2, ruleChainConnection.getFromIndex());
- Assert.assertEquals("Type index incorrect!", "Success", ruleChainConnection.getType());
+ Assert.assertEquals("Type index incorrect!", TbNodeConnectionType.SUCCESS, ruleChainConnection.getType());
Assert.assertEquals("Additional info incorrect!",
"{\"description\":\"\",\"layoutX\":477,\"layoutY\":560,\"ruleChainNodeId\":\"rule-chain-node-UNDEFINED\"}",
ruleChainConnection.getAdditionalInfo());
@@ -172,20 +176,20 @@ public class RuleChainMsgConstructorTest {
Assert.assertEquals("Connections count incorrect!", 10, ruleChainMetadataUpdateMsg.getConnectionsCount());
Assert.assertEquals("Rule chain connections count incorrect!", 1, ruleChainMetadataUpdateMsg.getRuleChainConnectionsCount());
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(0));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 0, "Attributes Updated"), ruleChainMetadataUpdateMsg.getConnections(1));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 3, "RPC Request from Device"), ruleChainMetadataUpdateMsg.getConnections(2));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 6, "Post telemetry"), ruleChainMetadataUpdateMsg.getConnections(3));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 5, "Post attributes"), ruleChainMetadataUpdateMsg.getConnections(4));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 2, "Other"), ruleChainMetadataUpdateMsg.getConnections(5));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 1, "RPC Request to Device"), ruleChainMetadataUpdateMsg.getConnections(6));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(7));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 0, "Success"), ruleChainMetadataUpdateMsg.getConnections(8));
- compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 4, "Success"), ruleChainMetadataUpdateMsg.getConnections(9));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(3, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(0));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 0, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(1));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 3, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(2));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 6, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(3));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 5, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(4));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 2, TbNodeConnectionType.OTHER), ruleChainMetadataUpdateMsg.getConnections(5));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(4, 1, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()), ruleChainMetadataUpdateMsg.getConnections(6));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(5, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(7));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(6, 0, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(8));
+ compareNodeConnectionInfoAndProto(createNodeConnectionInfo(7, 4, TbNodeConnectionType.SUCCESS), ruleChainMetadataUpdateMsg.getConnections(9));
RuleChainConnectionInfoProto ruleChainConnection = ruleChainMetadataUpdateMsg.getRuleChainConnections(0);
Assert.assertEquals("From index incorrect!", 7, ruleChainConnection.getFromIndex());
- Assert.assertEquals("Type index incorrect!", "Success", ruleChainConnection.getType());
+ Assert.assertEquals("Type index incorrect!", TbNodeConnectionType.SUCCESS, ruleChainConnection.getType());
Assert.assertEquals("Additional info incorrect!",
"{\"description\":\"\",\"layoutX\":477,\"layoutY\":560,\"ruleChainNodeId\":\"rule-chain-node-UNDEFINED\"}",
ruleChainConnection.getAdditionalInfo());
@@ -225,19 +229,19 @@ public class RuleChainMsgConstructorTest {
private List createConnections() {
List result = new ArrayList<>();
- result.add(createNodeConnectionInfo(3, 6, "Success"));
- result.add(createNodeConnectionInfo(3, 10, "Success"));
- result.add(createNodeConnectionInfo(3, 0, "Success"));
- result.add(createNodeConnectionInfo(4, 11, "Success"));
- result.add(createNodeConnectionInfo(5, 11, "Success"));
- result.add(createNodeConnectionInfo(6, 11, "Attributes Updated"));
- result.add(createNodeConnectionInfo(6, 7, "RPC Request from Device"));
- result.add(createNodeConnectionInfo(6, 4, "Post telemetry"));
- result.add(createNodeConnectionInfo(6, 5, "Post attributes"));
- result.add(createNodeConnectionInfo(6, 8, "Other"));
- result.add(createNodeConnectionInfo(6, 9, "RPC Request to Device"));
- result.add(createNodeConnectionInfo(7, 11, "Success"));
- result.add(createNodeConnectionInfo(10, 9, "RPC"));
+ result.add(createNodeConnectionInfo(3, 6, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(3, 10, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(3, 0, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(4, 11, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(5, 11, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(6, 11, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(6, 7, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(6, 4, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(6, 5, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(6, 8, TbNodeConnectionType.OTHER));
+ result.add(createNodeConnectionInfo(6, 9, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(7, 11, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(10, 9, RPC_CONNECTION_TYPE));
return result;
}
@@ -280,19 +284,19 @@ public class RuleChainMsgConstructorTest {
private List createConnectionsInDifferentOrder() {
List result = new ArrayList<>();
- result.add(createNodeConnectionInfo(0, 2, "RPC"));
- result.add(createNodeConnectionInfo(4, 1, "Success"));
- result.add(createNodeConnectionInfo(5, 1, "Attributes Updated"));
- result.add(createNodeConnectionInfo(5, 4, "RPC Request from Device"));
- result.add(createNodeConnectionInfo(5, 7, "Post telemetry"));
- result.add(createNodeConnectionInfo(5, 6, "Post attributes"));
- result.add(createNodeConnectionInfo(5, 3, "Other"));
- result.add(createNodeConnectionInfo(5, 2, "RPC Request to Device"));
- result.add(createNodeConnectionInfo(6, 1, "Success"));
- result.add(createNodeConnectionInfo(7, 1, "Success"));
- result.add(createNodeConnectionInfo(8, 11, "Success"));
- result.add(createNodeConnectionInfo(8, 5, "Success"));
- result.add(createNodeConnectionInfo(8, 0, "Success"));
+ result.add(createNodeConnectionInfo(0, 2, RPC_CONNECTION_TYPE));
+ result.add(createNodeConnectionInfo(4, 1, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(5, 1, TbMsgType.ATTRIBUTES_UPDATED.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(5, 4, TbMsgType.TO_SERVER_RPC_REQUEST.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(5, 7, TbMsgType.POST_TELEMETRY_REQUEST.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(5, 6, TbMsgType.POST_ATTRIBUTES_REQUEST.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(5, 3, TbNodeConnectionType.OTHER));
+ result.add(createNodeConnectionInfo(5, 2, TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.getRuleNodeConnection()));
+ result.add(createNodeConnectionInfo(6, 1, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(7, 1, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(8, 11, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(8, 5, TbNodeConnectionType.SUCCESS));
+ result.add(createNodeConnectionInfo(8, 0, TbNodeConnectionType.SUCCESS));
return result;
}
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 487783b454..229ea5d9f9 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
@@ -28,6 +28,7 @@ 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.AlarmInfo;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.dao.alarm.AlarmService;
@@ -42,7 +43,7 @@ import java.util.UUID;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -87,7 +88,7 @@ public class DefaultTbAlarmServiceTest {
.build());
service.save(alarm, new User());
- verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any());
+ verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ADDED), any());
verify(alarmSubscriptionService, times(1)).createAlarm(any());
}
@@ -95,11 +96,11 @@ public class DefaultTbAlarmServiceTest {
public void testAck() throws ThingsboardException {
var alarm = new Alarm();
when(alarmSubscriptionService.acknowledgeAlarm(any(), any(), anyLong()))
- .thenReturn(AlarmApiCallResult.builder().successful(true).modified(true).build());
+ .thenReturn(AlarmApiCallResult.builder().successful(true).modified(true).alarm(new AlarmInfo()).build());
service.ack(alarm, new User(new UserId(UUID.randomUUID())));
verify(alarmCommentService, times(1)).saveAlarmComment(any(), any(), any());
- verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any());
+ verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ALARM_ACK), any());
verify(alarmSubscriptionService, times(1)).acknowledgeAlarm(any(), any(), anyLong());
}
@@ -108,11 +109,11 @@ public class DefaultTbAlarmServiceTest {
var alarm = new Alarm();
alarm.setAcknowledged(true);
when(alarmSubscriptionService.clearAlarm(any(), any(), anyLong(), any()))
- .thenReturn(AlarmApiCallResult.builder().successful(true).cleared(true).build());
+ .thenReturn(AlarmApiCallResult.builder().successful(true).cleared(true).alarm(new AlarmInfo()).build());
service.clear(alarm, new User(new UserId(UUID.randomUUID())));
verify(alarmCommentService, times(1)).saveAlarmComment(any(), any(), any());
- verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any());
+ verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ALARM_CLEAR), any());
verify(alarmSubscriptionService, times(1)).clearAlarm(any(), any(), anyLong(), any());
}
@@ -120,7 +121,7 @@ public class DefaultTbAlarmServiceTest {
public void testDelete() {
service.delete(new Alarm(), new User());
- verify(notificationEntityService, times(1)).notifyDeleteAlarm(any(), any(), any(), any(), any(), any(), anyString());
+ verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.DELETED), any());
verify(alarmSubscriptionService, times(1)).deleteAlarm(any(), any());
}
-}
\ No newline at end of file
+}
diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java
index 29d9a6ebb8..50055b8d1a 100644
--- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java
@@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
+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.UserId;
@@ -81,7 +82,7 @@ public class DefaultTbAlarmCommentServiceTest {
when(alarmCommentService.createOrUpdateAlarmComment(Mockito.any(), eq(alarmComment))).thenReturn(alarmComment);
service.saveAlarmComment(alarm, alarmComment, new User());
- verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any());
+ verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ADDED_COMMENT), any(), any());
}
@Test
@@ -95,7 +96,7 @@ public class DefaultTbAlarmCommentServiceTest {
when(alarmCommentService.saveAlarmComment(Mockito.any(), eq(alarmComment))).thenReturn(alarmComment);
service.deleteAlarmComment(new Alarm(alarmId), alarmComment, new User());
- verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any());
+ verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.DELETED_COMMENT), any(), any());
}
@Test
diff --git a/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackCallbackTest.java b/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackCallbackTest.java
new file mode 100644
index 0000000000..80b9535af3
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/service/queue/TbMsgPackCallbackTest.java
@@ -0,0 +1,98 @@
+/**
+ * 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.queue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.rule.RuleNode;
+import org.thingsboard.server.common.msg.queue.RuleEngineException;
+import org.thingsboard.server.common.msg.queue.RuleNodeException;
+import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
+
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+class TbMsgPackCallbackTest {
+
+ TenantId tenantId;
+ UUID msgId;
+ TbMsgPackProcessingContext ctx;
+ TbMsgPackCallback callback;
+
+ @BeforeEach
+ void setUp() {
+ tenantId = TenantId.fromUUID(UUID.randomUUID());
+ msgId = UUID.randomUUID();
+ ctx = mock(TbMsgPackProcessingContext.class);
+ callback = spy(new TbMsgPackCallback(msgId, tenantId, ctx));
+ }
+
+ private static Stream testOnFailure_NotRateLimitException() {
+ return Stream.of(
+ Arguments.of(new RuleEngineException("rule engine no cause")),
+ Arguments.of(new RuleEngineException("rule engine caused 1 lvl", new RuntimeException())),
+ Arguments.of(new RuleEngineException("rule engine caused 2 lvl", new RuntimeException(new Exception()))),
+ Arguments.of(new RuleEngineException("rule engine caused 2 lvl Throwable", new RuntimeException(new Throwable()))),
+ Arguments.of(new RuleNodeException("rule node no cause", "RuleChain", new RuleNode()))
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testOnFailure_NotRateLimitException(RuleEngineException ree) {
+ callback.onFailure(ree);
+
+ verify(callback, never()).onRateLimit(any());
+ verify(callback, never()).onSuccess();
+ verify(ctx, never()).onSuccess(any());
+ }
+
+ private static Stream testOnFailure_RateLimitException() {
+ return Stream.of(
+ Arguments.of(new RuleEngineException("caused lvl 1", new TbRateLimitsException(EntityType.ASSET))),
+ Arguments.of(new RuleEngineException("caused lvl 2", new RuntimeException(new TbRateLimitsException(EntityType.ASSET)))),
+ Arguments.of(
+ new RuleEngineException("caused lvl 3",
+ new RuntimeException(
+ new Exception(
+ new TbRateLimitsException(EntityType.ASSET)))))
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testOnFailure_RateLimitException(RuleEngineException ree) {
+ callback.onFailure(ree);
+
+ verify(callback).onRateLimit(any());
+ verify(callback).onFailure(any());
+ verify(callback, never()).onSuccess();
+ verify(ctx).onSuccess(msgId);
+ verify(ctx).onSuccess(any());
+ verify(ctx, never()).onFailure(any(), any(), any());
+ }
+
+}
diff --git a/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java
index 4373a4c108..5cd54a24eb 100644
--- a/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java
@@ -33,6 +33,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
@DaoSqlTest
@TestPropertySource(properties = {
@@ -121,7 +122,7 @@ class NashornJsInvokeServiceTest extends AbstractControllerTest {
}
private String invokeScript(UUID scriptId, String msg) throws ExecutionException, InterruptedException {
- return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", "POST_TELEMETRY_REQUEST").get().toString();
+ return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString();
}
}
diff --git a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java
index ca5dbef5f1..62af9cb16e 100644
--- a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java
@@ -42,6 +42,7 @@ import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
@DaoSqlTest
@TestPropertySource(properties = {
@@ -216,7 +217,7 @@ class TbelInvokeServiceTest extends AbstractControllerTest {
private String invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException {
var msg = JacksonUtil.fromString(str, Map.class);
- return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", "POST_TELEMETRY_REQUEST").get().toString();
+ return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString();
}
}
diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java
index e70a888194..654f934ed2 100644
--- a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java
@@ -33,11 +33,11 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.security.Authority;
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.common.msg.session.SessionMsgType;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
@@ -133,7 +133,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest
void saveLatestTsForAssetAndDevice(List devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException {
for (Device device : devices) {
- TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(),
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST,
device.getId(),
getTbMsgMetadata(device.getName(), ts.get(idx)),
TbMsgDataType.JSON,
diff --git a/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java b/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java
index 39b61c6c47..b9b023e9e9 100644
--- a/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java
+++ b/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java
@@ -52,6 +52,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.relation.EntityRelation;
@@ -343,7 +344,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
- metaData.addConnectionInfo(0, 1, "Success");
+ metaData.addConnectionInfo(0, 1, TbNodeConnectionType.SUCCESS);
ruleChainService.saveRuleChainMetaData(tenantId, metaData, Function.identity());
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());
@@ -381,7 +382,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
- metaData.addConnectionInfo(0, 1, "Success");
+ metaData.addConnectionInfo(0, 1, TbNodeConnectionType.SUCCESS);
ruleChainService.saveRuleChainMetaData(tenantId, metaData, Function.identity());
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());
diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java
index 8962a35187..e81aaed39d 100644
--- a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java
+++ b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java
@@ -80,8 +80,6 @@ public interface TbClusterService extends TbQueueClusterService {
void onDeviceUpdated(Device device, Device old);
- void onDeviceUpdated(Device device, Device old, boolean notifyEdge);
-
void onDeviceDeleted(Device device, TbQueueCallback callback);
void onResourceChange(TbResource resource, TbQueueCallback callback);
diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java
new file mode 100644
index 0000000000..90355d885d
--- /dev/null
+++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java
@@ -0,0 +1,29 @@
+/**
+ * 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.device;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.springframework.core.io.Resource;
+import org.thingsboard.server.common.data.Device;
+
+import java.net.URISyntaxException;
+
+public interface DeviceConnectivityService {
+
+ JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException;
+
+ Resource getPemCertFile(String protocol);
+}
diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbRelationTypes.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java
similarity index 74%
rename from rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbRelationTypes.java
rename to common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java
index 2535762ad5..8cce581098 100644
--- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbRelationTypes.java
+++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java
@@ -13,14 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.rule.engine.api;
+package org.thingsboard.server.dao.edge;
-/**
- * Created by ashvayka on 19.01.18.
- */
-public final class TbRelationTypes {
+public interface EdgeSynchronizationManager {
- public static String SUCCESS = "Success";
- public static String FAILURE = "Failure";
+ ThreadLocal getSync();
+ boolean isSync();
}
diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
index 3ddb6187ea..39e94b3a6b 100644
--- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
+++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
@@ -53,6 +53,8 @@ public interface RelationService {
void deleteEntityRelations(TenantId tenantId, EntityId entity);
+ void deleteEntityCommonRelations(TenantId tenantId, EntityId entity);
+
List findByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup);
ListenableFuture> findByFromAsync(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup);
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 e1f16be1ed..47a7423191 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
@@ -39,7 +39,7 @@ public interface UserService extends EntityDaoService {
User findUserByTenantIdAndEmail(TenantId tenantId, String email);
- User saveUser(User user);
+ User saveUser(TenantId tenantId, User user);
UserCredentials findUserCredentialsByUserId(TenantId tenantId, UserId userId);
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
index 0f0cf0467f..02871a59b6 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
@@ -109,6 +109,7 @@ public class DataConstants {
public static final String PROVISION_KEY = "provisionDeviceKey";
public static final String PROVISION_SECRET = "provisionDeviceSecret";
+ public static final String DEFAULT_DEVICE_TYPE = "default";
public static final String DEVICE_NAME = "deviceName";
public static final String DEVICE_TYPE = "deviceType";
public static final String CERT_PUB_KEY = "x509CertPubKey";
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityFieldsData.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityFieldsData.java
index c88a6b970f..db069d8d61 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityFieldsData.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityFieldsData.java
@@ -68,20 +68,22 @@ public class EntityFieldsData {
break;
}
}
- if (current != null) {
- if(current.isNull() && ignoreNullStrings){
+ if (current == null) {
+ return null;
+ }
+ if (current.isNull() && ignoreNullStrings) {
+ return null;
+ }
+ if (current.isValueNode()) {
+ String textValue = current.asText();
+ if (StringUtils.isEmpty(textValue) && ignoreNullStrings) {
return null;
}
- if (current.isValueNode()) {
- return current.asText();
- } else {
- try {
- return mapper.writeValueAsString(current);
- } catch (JsonProcessingException e) {
- return null;
- }
- }
- } else {
+ return textValue;
+ }
+ try {
+ return mapper.writeValueAsString(current);
+ } catch (JsonProcessingException e) {
return null;
}
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
index 572dc16c0b..8ca6585718 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
@@ -18,6 +18,10 @@ package org.thingsboard.server.common.data;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
/**
* @author Andrew Shvayka
*/
@@ -31,7 +35,13 @@ public enum EntityType {
ALARM,
RULE_CHAIN,
RULE_NODE,
- ENTITY_VIEW,
+ ENTITY_VIEW {
+ // backward compatibility for TbOriginatorTypeSwitchNode to return correct rule node connection.
+ @Override
+ public String getNormalName() {
+ return "Entity View";
+ }
+ },
WIDGETS_BUNDLE,
WIDGET_TYPE,
TENANT_PROFILE,
@@ -49,6 +59,9 @@ public enum EntityType {
NOTIFICATION,
NOTIFICATION_RULE;
+ public static final List NORMAL_NAMES = EnumSet.allOf(EntityType.class).stream()
+ .map(EntityType::getNormalName).collect(Collectors.toUnmodifiableList());
+
@Getter
private final String normalName = StringUtils.capitalize(StringUtils.removeStart(name(), "TB_")
.toLowerCase().replaceAll("_", " "));
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
index 01009751d4..056be5a958 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
@@ -16,49 +16,61 @@
package org.thingsboard.server.common.data.audit;
import lombok.Getter;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+
+import java.util.Optional;
-@Getter
public enum ActionType {
- ADDED(false), // log entity
- DELETED(false), // log string id
- UPDATED(false), // log entity
- ATTRIBUTES_UPDATED(false), // log attributes/values
- ATTRIBUTES_DELETED(false), // log attributes
- TIMESERIES_UPDATED(false), // log timeseries update
- TIMESERIES_DELETED(false), // log timeseries
- RPC_CALL(false), // log method and params
- CREDENTIALS_UPDATED(false), // log new credentials
- ASSIGNED_TO_CUSTOMER(false), // log customer name
- UNASSIGNED_FROM_CUSTOMER(false), // log customer name
- ACTIVATED(false), // log string id
- SUSPENDED(false), // log string id
- CREDENTIALS_READ(true), // log device id
- ATTRIBUTES_READ(true), // log attributes
- RELATION_ADD_OR_UPDATE(false),
- RELATION_DELETED(false),
- RELATIONS_DELETED(false),
- ALARM_ACK(false),
- ALARM_CLEAR(false),
- ALARM_DELETE(false),
- ALARM_ASSIGNED(false),
- ALARM_UNASSIGNED(false),
- LOGIN(false),
- LOGOUT(false),
- LOCKOUT(false),
- ASSIGNED_FROM_TENANT(false),
- ASSIGNED_TO_TENANT(false),
- PROVISION_SUCCESS(false),
- PROVISION_FAILURE(false),
- ASSIGNED_TO_EDGE(false), // log edge name
- UNASSIGNED_FROM_EDGE(false),
- ADDED_COMMENT(false),
- UPDATED_COMMENT(false),
- DELETED_COMMENT(false),
- SMS_SENT(false);
+ ADDED(false, TbMsgType.ENTITY_CREATED), // log entity
+ DELETED(false, TbMsgType.ENTITY_DELETED), // log string id
+ UPDATED(false, TbMsgType.ENTITY_UPDATED), // log entity
+ ATTRIBUTES_UPDATED(false, TbMsgType.ATTRIBUTES_UPDATED), // log attributes/values
+ ATTRIBUTES_DELETED(false, TbMsgType.ATTRIBUTES_DELETED), // log attributes
+ TIMESERIES_UPDATED(false, TbMsgType.TIMESERIES_UPDATED), // log timeseries update
+ TIMESERIES_DELETED(false, TbMsgType.TIMESERIES_DELETED), // log timeseries
+ RPC_CALL(false, null), // log method and params
+ CREDENTIALS_UPDATED(false, null), // log new credentials
+ ASSIGNED_TO_CUSTOMER(false, TbMsgType.ENTITY_ASSIGNED), // log customer name
+ UNASSIGNED_FROM_CUSTOMER(false, TbMsgType.ENTITY_UNASSIGNED), // log customer name
+ ACTIVATED(false, null), // log string id
+ SUSPENDED(false, null), // log string id
+ CREDENTIALS_READ(true, null), // log device id
+ ATTRIBUTES_READ(true, null), // log attributes
+ RELATION_ADD_OR_UPDATE(false, TbMsgType.RELATION_ADD_OR_UPDATE),
+ RELATION_DELETED(false, TbMsgType.RELATION_DELETED),
+ RELATIONS_DELETED(false, TbMsgType.RELATIONS_DELETED),
+ ALARM_ACK(false, TbMsgType.ALARM_ACK),
+ ALARM_CLEAR(false, TbMsgType.ALARM_CLEAR),
+ ALARM_DELETE(false, TbMsgType.ALARM_DELETE),
+ ALARM_ASSIGNED(false, TbMsgType.ALARM_ASSIGNED),
+ ALARM_UNASSIGNED(false, TbMsgType.ALARM_UNASSIGNED),
+ LOGIN(false, null),
+ LOGOUT(false, null),
+ LOCKOUT(false, null),
+ ASSIGNED_FROM_TENANT(false, TbMsgType.ENTITY_ASSIGNED_FROM_TENANT),
+ ASSIGNED_TO_TENANT(false, TbMsgType.ENTITY_ASSIGNED_TO_TENANT),
+ PROVISION_SUCCESS(false, TbMsgType.PROVISION_SUCCESS),
+ PROVISION_FAILURE(false, TbMsgType.PROVISION_FAILURE),
+ ASSIGNED_TO_EDGE(false, TbMsgType.ENTITY_ASSIGNED_TO_EDGE), // log edge name
+ UNASSIGNED_FROM_EDGE(false, TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE),
+ ADDED_COMMENT(false, TbMsgType.COMMENT_CREATED),
+ UPDATED_COMMENT(false, TbMsgType.COMMENT_UPDATED),
+ DELETED_COMMENT(false, null),
+ SMS_SENT(false, null);
+
+ @Getter
private final boolean isRead;
- ActionType(boolean isRead) {
+ private final TbMsgType ruleEngineMsgType;
+
+ ActionType(boolean isRead, TbMsgType ruleEngineMsgType) {
this.isRead = isRead;
+ this.ruleEngineMsgType = ruleEngineMsgType;
}
+
+ public Optional getRuleEngineMsgType() {
+ return Optional.ofNullable(ruleEngineMsgType);
+ }
+
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
index 756c30690f..be54b70f18 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
@@ -15,24 +15,33 @@
*/
package org.thingsboard.server.common.data.edge;
+import lombok.Getter;
+
+@Getter
public enum EdgeEventType {
- DASHBOARD,
- ASSET,
- DEVICE,
- DEVICE_PROFILE,
- ASSET_PROFILE,
- ENTITY_VIEW,
- ALARM,
- RULE_CHAIN,
- RULE_CHAIN_METADATA,
- EDGE,
- USER,
- CUSTOMER,
- RELATION,
- TENANT,
- WIDGETS_BUNDLE,
- WIDGET_TYPE,
- ADMIN_SETTINGS,
- OTA_PACKAGE,
- QUEUE
+ DASHBOARD(false),
+ ASSET(false),
+ DEVICE(false),
+ DEVICE_PROFILE(true),
+ ASSET_PROFILE(true),
+ ENTITY_VIEW(false),
+ ALARM(false),
+ RULE_CHAIN(false),
+ RULE_CHAIN_METADATA(false),
+ EDGE(false),
+ USER(true),
+ CUSTOMER(true),
+ RELATION(true),
+ TENANT(true),
+ WIDGETS_BUNDLE(true),
+ WIDGET_TYPE(true),
+ ADMIN_SETTINGS(true),
+ OTA_PACKAGE(true),
+ QUEUE(true);
+
+ private final boolean allEdgesRelated;
+
+ EdgeEventType(boolean allEdgesRelated) {
+ this.allEdgesRelated = allEdgesRelated;
+ }
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/exception/AbstractRateLimitException.java b/common/data/src/main/java/org/thingsboard/server/common/data/exception/AbstractRateLimitException.java
new file mode 100644
index 0000000000..1d1da75da3
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/exception/AbstractRateLimitException.java
@@ -0,0 +1,41 @@
+/**
+ * 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.common.data.exception;
+
+public abstract class AbstractRateLimitException extends RuntimeException {
+
+ public AbstractRateLimitException() {
+ super();
+ }
+
+ public AbstractRateLimitException(String message) {
+ super(message);
+ }
+
+ public AbstractRateLimitException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AbstractRateLimitException(Throwable cause) {
+ super(cause);
+ }
+
+ protected AbstractRateLimitException(String message, Throwable cause,
+ boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/exception/ApiUsageLimitsExceededException.java b/common/data/src/main/java/org/thingsboard/server/common/data/exception/ApiUsageLimitsExceededException.java
index 2d24184a3f..aa9441c776 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/exception/ApiUsageLimitsExceededException.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/exception/ApiUsageLimitsExceededException.java
@@ -15,7 +15,7 @@
*/
package org.thingsboard.server.common.data.exception;
-public class ApiUsageLimitsExceededException extends RuntimeException {
+public class ApiUsageLimitsExceededException extends AbstractRateLimitException {
public ApiUsageLimitsExceededException(String message) {
super(message);
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java
index dee0e7aa9b..a97cc8f834 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseDeleteTsKvQuery.java
@@ -21,14 +21,20 @@ import lombok.Data;
public class BaseDeleteTsKvQuery extends BaseTsKvQuery implements DeleteTsKvQuery {
private final Boolean rewriteLatestIfDeleted;
+ private final Boolean deleteLatest;
- public BaseDeleteTsKvQuery(String key, long startTs, long endTs, boolean rewriteLatestIfDeleted) {
+ public BaseDeleteTsKvQuery(String key, long startTs, long endTs, boolean rewriteLatestIfDeleted, boolean deleteLatest) {
super(key, startTs, endTs);
this.rewriteLatestIfDeleted = rewriteLatestIfDeleted;
+ this.deleteLatest = deleteLatest;
+ }
+
+ public BaseDeleteTsKvQuery(String key, long startTs, long endTs, boolean rewriteLatestIfDeleted) {
+ this(key, startTs, endTs, rewriteLatestIfDeleted, true);
}
public BaseDeleteTsKvQuery(String key, long startTs, long endTs) {
- this(key, startTs, endTs, false);
+ this(key, startTs, endTs, false, true);
}
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/DeleteTsKvQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/DeleteTsKvQuery.java
index 7b9b4ad16f..b2f41fffb4 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/DeleteTsKvQuery.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/DeleteTsKvQuery.java
@@ -19,4 +19,6 @@ public interface DeleteTsKvQuery extends TsKvQuery {
Boolean getRewriteLatestIfDeleted();
+ Boolean getDeleteLatest();
+
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java
new file mode 100644
index 0000000000..206b203682
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java
@@ -0,0 +1,115 @@
+/**
+ * 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.common.data.msg;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public enum TbMsgType {
+
+ POST_ATTRIBUTES_REQUEST("Post attributes"),
+ POST_TELEMETRY_REQUEST("Post telemetry"),
+ TO_SERVER_RPC_REQUEST("RPC Request from Device"),
+ ACTIVITY_EVENT("Activity Event"),
+ INACTIVITY_EVENT("Inactivity Event"),
+ CONNECT_EVENT("Connect Event"),
+ DISCONNECT_EVENT("Disconnect Event"),
+ ENTITY_CREATED("Entity Created"),
+ ENTITY_UPDATED("Entity Updated"),
+ ENTITY_DELETED("Entity Deleted"),
+ ENTITY_ASSIGNED("Entity Assigned"),
+ ENTITY_UNASSIGNED("Entity Unassigned"),
+ ATTRIBUTES_UPDATED("Attributes Updated"),
+ ATTRIBUTES_DELETED("Attributes Deleted"),
+ ALARM(null),
+ ALARM_ACK("Alarm Acknowledged"),
+ ALARM_CLEAR("Alarm Cleared"),
+ ALARM_DELETE(null),
+ ALARM_ASSIGNED("Alarm Assigned"),
+ ALARM_UNASSIGNED("Alarm Unassigned"),
+ COMMENT_CREATED("Comment Created"),
+ COMMENT_UPDATED("Comment Updated"),
+ RPC_CALL_FROM_SERVER_TO_DEVICE("RPC Request to Device"),
+ ENTITY_ASSIGNED_FROM_TENANT("Entity Assigned From Tenant"),
+ ENTITY_ASSIGNED_TO_TENANT("Entity Assigned To Tenant"),
+ ENTITY_ASSIGNED_TO_EDGE(null),
+ ENTITY_UNASSIGNED_FROM_EDGE(null),
+ TIMESERIES_UPDATED("Timeseries Updated"),
+ TIMESERIES_DELETED("Timeseries Deleted"),
+ RPC_QUEUED("RPC Queued"),
+ RPC_SENT("RPC Sent"),
+ RPC_DELIVERED("RPC Delivered"),
+ RPC_SUCCESSFUL("RPC Successful"),
+ RPC_TIMEOUT("RPC Timeout"),
+ RPC_EXPIRED("RPC Expired"),
+ RPC_FAILED("RPC Failed"),
+ RPC_DELETED("RPC Deleted"),
+ RELATION_ADD_OR_UPDATE("Relation Added or Updated"),
+ RELATION_DELETED("Relation Deleted"),
+ RELATIONS_DELETED("All Relations Deleted"),
+ PROVISION_SUCCESS(null),
+ PROVISION_FAILURE(null),
+ SEND_EMAIL(null),
+
+ // tellSelfOnly types
+ GENERATOR_NODE_SELF_MSG(null, true),
+ DEVICE_PROFILE_PERIODIC_SELF_MSG(null, true),
+ DEVICE_PROFILE_UPDATE_SELF_MSG(null, true),
+ DEVICE_UPDATE_SELF_MSG(null, true),
+ DEDUPLICATION_TIMEOUT_SELF_MSG(null, true),
+ DELAY_TIMEOUT_SELF_MSG(null, true),
+ MSG_COUNT_SELF_MSG(null, true);
+
+ public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream()
+ .filter(tbMsgType -> !tbMsgType.isTellSelfOnly())
+ .map(TbMsgType::getRuleNodeConnection)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toUnmodifiableList());
+
+ @Getter
+ private final String ruleNodeConnection;
+
+ @Getter
+ private final boolean tellSelfOnly;
+
+ TbMsgType(String ruleNodeConnection, boolean tellSelfOnly) {
+ this.ruleNodeConnection = ruleNodeConnection;
+ this.tellSelfOnly = tellSelfOnly;
+ }
+
+ TbMsgType(String ruleNodeConnection) {
+ this.ruleNodeConnection = ruleNodeConnection;
+ this.tellSelfOnly = false;
+ }
+
+ public static String getRuleNodeConnectionOrElseOther(String msgType) {
+ if (msgType == null) {
+ return TbNodeConnectionType.OTHER;
+ } else {
+ return Arrays.stream(TbMsgType.values())
+ .filter(type -> type.name().equals(msgType))
+ .findFirst()
+ .map(TbMsgType::getRuleNodeConnection)
+ .orElse(TbNodeConnectionType.OTHER);
+ }
+ }
+
+}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbNodeConnectionType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbNodeConnectionType.java
new file mode 100644
index 0000000000..584393bf53
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbNodeConnectionType.java
@@ -0,0 +1,31 @@
+/**
+ * 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.common.data.msg;
+
+/**
+ * Created by ashvayka on 19.01.18.
+ */
+public final class TbNodeConnectionType {
+
+ public static final String SUCCESS = "Success";
+ public static final String FAILURE = "Failure";
+
+ public static final String TRUE = "True";
+ public static final String FALSE = "False";
+
+ public static final String OTHER = "Other";
+
+}
diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java
new file mode 100644
index 0000000000..9eee9ec23d
--- /dev/null
+++ b/common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java
@@ -0,0 +1,30 @@
+/**
+ * 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.common.data;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class EntityTypeTest {
+
+ // backward-compatibility test
+ @Test
+ void getNormalNameTest() {
+ assertThat(EntityType.ENTITY_VIEW.getNormalName()).isEqualTo("Entity View");
+ }
+
+}
diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java
new file mode 100644
index 0000000000..8c602c3cff
--- /dev/null
+++ b/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.common.data.audit;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.thingsboard.server.common.data.audit.ActionType.ACTIVATED;
+import static org.thingsboard.server.common.data.audit.ActionType.ATTRIBUTES_READ;
+import static org.thingsboard.server.common.data.audit.ActionType.CREDENTIALS_READ;
+import static org.thingsboard.server.common.data.audit.ActionType.CREDENTIALS_UPDATED;
+import static org.thingsboard.server.common.data.audit.ActionType.DELETED_COMMENT;
+import static org.thingsboard.server.common.data.audit.ActionType.LOCKOUT;
+import static org.thingsboard.server.common.data.audit.ActionType.LOGIN;
+import static org.thingsboard.server.common.data.audit.ActionType.LOGOUT;
+import static org.thingsboard.server.common.data.audit.ActionType.RPC_CALL;
+import static org.thingsboard.server.common.data.audit.ActionType.SMS_SENT;
+import static org.thingsboard.server.common.data.audit.ActionType.SUSPENDED;
+
+class ActionTypeTest {
+
+ private static final List typesWithNullRuleEngineMsgType = List.of(
+ RPC_CALL,
+ CREDENTIALS_UPDATED,
+ ACTIVATED,
+ SUSPENDED,
+ CREDENTIALS_READ,
+ ATTRIBUTES_READ,
+ LOGIN,
+ LOGOUT,
+ LOCKOUT,
+ DELETED_COMMENT,
+ SMS_SENT
+ );
+
+ // backward-compatibility tests
+
+ @Test
+ void getRuleEngineMsgTypeTest() {
+ var types = ActionType.values();
+ for (var type : types) {
+ if (typesWithNullRuleEngineMsgType.contains(type)) {
+ assertThat(type.getRuleEngineMsgType()).isEmpty();
+ } else {
+ assertThat(type.getRuleEngineMsgType()).isPresent();
+ }
+ }
+ }
+
+}
diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java
new file mode 100644
index 0000000000..a37eb31d72
--- /dev/null
+++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java
@@ -0,0 +1,87 @@
+/**
+ * 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.common.data.msg;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM;
+import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE;
+import static org.thingsboard.server.common.data.msg.TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.DELAY_TIMEOUT_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_TO_EDGE;
+import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE;
+import static org.thingsboard.server.common.data.msg.TbMsgType.MSG_COUNT_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_FAILURE;
+import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_SUCCESS;
+import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_UPDATE_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.GENERATOR_NODE_SELF_MSG;
+import static org.thingsboard.server.common.data.msg.TbMsgType.SEND_EMAIL;
+
+class TbMsgTypeTest {
+
+ private static final List typesWithNullRuleNodeConnection = List.of(
+ ALARM,
+ ALARM_DELETE,
+ ENTITY_ASSIGNED_TO_EDGE,
+ ENTITY_UNASSIGNED_FROM_EDGE,
+ PROVISION_FAILURE,
+ PROVISION_SUCCESS,
+ SEND_EMAIL,
+ GENERATOR_NODE_SELF_MSG,
+ DEVICE_PROFILE_PERIODIC_SELF_MSG,
+ DEVICE_PROFILE_UPDATE_SELF_MSG,
+ DEVICE_UPDATE_SELF_MSG,
+ DEDUPLICATION_TIMEOUT_SELF_MSG,
+ DELAY_TIMEOUT_SELF_MSG,
+ MSG_COUNT_SELF_MSG
+ );
+
+ // backward-compatibility tests
+
+ @Test
+ void getRuleNodeConnectionsTest() {
+ var tbMsgTypes = TbMsgType.values();
+ for (var type : tbMsgTypes) {
+ if (typesWithNullRuleNodeConnection.contains(type)) {
+ assertThat(type.getRuleNodeConnection()).isNull();
+ } else {
+ assertThat(type.getRuleNodeConnection()).isNotNull();
+ }
+ }
+ }
+
+ @Test
+ void getRuleNodeConnectionOrElseOtherTest() {
+ assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(null))
+ .isEqualTo(TbNodeConnectionType.OTHER);
+ var tbMsgTypes = TbMsgType.values();
+ for (var type : tbMsgTypes) {
+ if (typesWithNullRuleNodeConnection.contains(type)) {
+ assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name()))
+ .isEqualTo(TbNodeConnectionType.OTHER);
+ } else {
+ assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name())).isNotNull()
+ .isNotEqualTo(TbNodeConnectionType.OTHER);
+ }
+ }
+ }
+
+}
diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
index 17bc7c0a8f..a987a4a253 100644
--- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
+++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
@@ -29,10 +29,12 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.gen.MsgProtos;
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
import java.io.Serializable;
+import java.util.Objects;
import java.util.UUID;
/**
@@ -42,6 +44,10 @@ import java.util.UUID;
@Slf4j
public final class TbMsg implements Serializable {
+ public static final String EMPTY_JSON_OBJECT = "{}";
+ public static final String EMPTY_JSON_ARRAY = "[]";
+ public static final String EMPTY_STRING = "";
+
private final String queueName;
private final UUID id;
private final long ts;
@@ -66,82 +72,234 @@ public final class TbMsg implements Serializable {
return ctx.getAndIncrementRuleNodeCounter();
}
+ @Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId);
}
+ /**
+ * Creates a new TbMsg instance with the specified parameters.
+ *
+ * Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to
+ * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
+ * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String, RuleChainId, RuleNodeId)}
+ * method instead.
+ *
+ * @param queueName the name of the queue where the message will be sent
+ * @param type the type of the message
+ * @param originator the originator of the message
+ * @param customerId the ID of the customer associated with the message
+ * @param metaData the metadata of the message
+ * @param data the data of the message
+ * @param ruleChainId the ID of the rule chain associated with the message
+ * @param ruleNodeId the ID of the rule node associated with the message
+ * @return new TbMsg instance
+ */
+ @Deprecated(since = "3.5.2")
public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
}
+ @Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(type, originator, null, metaData, data);
}
+ @Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
}
+ public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
+ return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId);
+ }
+
+ public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
+ return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
+ metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
+ }
+
+ public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
+ return newMsg(type, originator, null, metaData, data);
+ }
+
+ public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
+ return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
+ metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
+ }
+
// REALLY NEW MSG
+ /**
+ * Creates a new TbMsg instance with the specified parameters.
+ *
+ * Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to
+ * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
+ * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, TbMsgMetaData, String)}
+ * method instead.
+ *
+ * @param queueName the name of the queue where the message will be sent
+ * @param type the type of the message
+ * @param originator the originator of the message
+ * @param metaData the metadata of the message
+ * @param data the data of the message
+ * @return new TbMsg instance
+ */
+ @Deprecated(since = "3.5.2")
public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueName, type, originator, null, metaData, data);
}
+ /**
+ * Creates a new TbMsg instance with the specified parameters.
+ *
+ * Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to
+ * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
+ * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String)}
+ * method instead.
+ *
+ * @param queueName the name of the queue where the message will be sent
+ * @param type the type of the message
+ * @param originator the originator of the message
+ * @param customerId the ID of the customer associated with the message
+ * @param metaData the metadata of the message
+ * @param data the data of the message
+ * @return new TbMsg instance
+ */
+ @Deprecated(since = "3.5.2")
public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
}
+ @Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY);
}
+ /**
+ * Creates a new TbMsg instance with the specified parameters.
+ *
+ * Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to
+ * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
+ * it is recommended to use the {@link #newMsg(TbMsgType, EntityId, TbMsgMetaData, TbMsgDataType, String)}
+ * method instead.
+ *
+ * @param type the type of the message
+ * @param originator the originator of the message
+ * @param metaData the metadata of the message
+ * @param dataType the dataType of the message
+ * @param data the data of the message
+ * @return new TbMsg instance
+ */
+ @Deprecated(since = "3.5.2")
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
return newMsg(type, originator, null, metaData, dataType, data);
}
+ public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
+ return newMsg(queueName, type, originator, null, metaData, data);
+ }
+
+ public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
+ return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
+ metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
+ }
+
+ public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
+ return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId,
+ metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY);
+ }
+
+ public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
+ return newMsg(type, originator, null, metaData, dataType, data);
+ }
+
// For Tests only
+ @Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null,
metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
}
+ @Deprecated(since = "3.5.2", forRemoval = true)
public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) {
return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback);
}
+ /**
+ * Transforms an existing TbMsg instance by changing its message type, originator, metadata, and data.
+ *
+ * Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to
+ * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types,
+ * it is recommended to use the {@link #transformMsg(TbMsg, TbMsgType, EntityId, TbMsgMetaData, String)}
+ * method instead.
+ *
+ *
+ * @param tbMsg the TbMsg instance to transform
+ * @param type the new message type
+ * @param originator the new originator
+ * @param metaData the new metadata
+ * @param data the new data
+ * @return the transformed TbMsg instance
+ */
+ @Deprecated(since = "3.5.2")
public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback);
}
+ public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
+ return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null,
+ metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
+ }
+
+ public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) {
+ return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null,
+ metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback);
+ }
+
+ public static TbMsg transformMsg(TbMsg tbMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) {
+ return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type.name(), originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType,
+ data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback);
+ }
+
+ public static TbMsg transformMsgOriginator(TbMsg tbMsg, EntityId originatorId) {
+ return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, originatorId, tbMsg.getCustomerId(), tbMsg.metaData, tbMsg.dataType,
+ tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
+ }
+
public static TbMsg transformMsgData(TbMsg tbMsg, String data) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
- public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata) {
+ public static TbMsg transformMsgMetadata(TbMsg tbMsg, TbMsgMetaData metadata) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType,
tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
- public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) {
+ public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata, String data) {
+ return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata, tbMsg.dataType,
+ data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
+ }
+
+ public static TbMsg transformMsgCustomerId(TbMsg tbMsg, CustomerId customerId) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
}
- public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) {
+ public static TbMsg transformMsgRuleChainId(TbMsg tbMsg, RuleChainId ruleChainId) {
return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback());
}
- public static TbMsg transformMsg(TbMsg tbMsg, String queueName) {
+ public static TbMsg transformMsgQueueName(TbMsg tbMsg, String queueName) {
return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback());
}
@@ -183,11 +341,7 @@ public final class TbMsg implements Serializable {
this.ruleChainId = ruleChainId;
this.ruleNodeId = ruleNodeId;
this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx();
- if (callback != null) {
- this.callback = callback;
- } else {
- this.callback = TbMsgCallback.EMPTY;
- }
+ this.callback = Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY);
}
public static ByteString toByteString(TbMsg msg) {
@@ -284,11 +438,7 @@ public final class TbMsg implements Serializable {
public TbMsgCallback getCallback() {
// May be null in case of deserialization;
- if (callback != null) {
- return callback;
- } else {
- return TbMsgCallback.EMPTY;
- }
+ return Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY);
}
public void pushToStack(RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
@@ -317,4 +467,18 @@ public final class TbMsg implements Serializable {
}
return ts;
}
+
+ public boolean isTypeOf(TbMsgType tbMsgType) {
+ return tbMsgType != null && tbMsgType.name().equals(this.type);
+ }
+
+ public boolean isTypeOneOf(TbMsgType... types) {
+ for (TbMsgType type : types) {
+ if (isTypeOf(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java
index 1724a9050f..b8c713cc6b 100644
--- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java
+++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java
@@ -32,6 +32,11 @@ public class RuleEngineException extends Exception {
ts = System.currentTimeMillis();
}
+ public RuleEngineException(String message, Throwable t) {
+ super(message != null ? message : "Unknown", t);
+ ts = System.currentTimeMillis();
+ }
+
public String toJsonString() {
try {
return mapper.writeValueAsString(mapper.createObjectNode().put("message", getMessage()));
diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java
index 3312c98b64..6cf298adb2 100644
--- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java
+++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbMsgCallback.java
@@ -39,6 +39,10 @@ public interface TbMsgCallback {
void onFailure(RuleEngineException e);
+ default void onRateLimit(RuleEngineException e) {
+ onFailure(e);
+ };
+
/**
* Returns 'true' if rule engine is expecting the message to be processed, 'false' otherwise.
* message may no longer be valid, if the message pack is already expired/canceled/failed.
diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java
index dfcf178473..ca7c94e9ce 100644
--- a/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java
+++ b/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java
@@ -15,6 +15,12 @@
*/
package org.thingsboard.server.common.msg.session;
+/**
+ * @deprecated This enum is deprecated and will be removed in a future version.
+ * Note: This enum was originally part of the public API but is now specific to CoAP transport only.
+ * Please use {@link org.thingsboard.server.transport.coap.CoapSessionMsgType} instead.
+ */
+@Deprecated(since="3.5.2", forRemoval = true)
public enum SessionMsgType {
GET_ATTRIBUTES_REQUEST(true), POST_ATTRIBUTES_REQUEST(true), GET_ATTRIBUTES_RESPONSE,
SUBSCRIBE_ATTRIBUTES_REQUEST, UNSUBSCRIBE_ATTRIBUTES_REQUEST, ATTRIBUTES_UPDATE_NOTIFICATION,
diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java
index dd5fda4dd5..5e63cb037e 100644
--- a/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java
+++ b/common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java
@@ -17,11 +17,12 @@ package org.thingsboard.server.common.msg.tools;
import lombok.Getter;
import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.exception.AbstractRateLimitException;
/**
* Created by ashvayka on 22.10.18.
*/
-public class TbRateLimitsException extends RuntimeException {
+public class TbRateLimitsException extends AbstractRateLimitException {
@Getter
private final EntityType entityType;
diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueCallbackWrapper.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueCallbackWrapper.java
index f14c9a047b..f102e34666 100644
--- a/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueCallbackWrapper.java
+++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueCallbackWrapper.java
@@ -40,6 +40,6 @@ public class MultipleTbQueueCallbackWrapper implements TbQueueCallback {
@Override
public void onFailure(Throwable t) {
- callback.onFailure(new RuleEngineException(t.getMessage()));
+ callback.onFailure(new RuleEngineException(t.getMessage(), t));
}
}
diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueTbMsgCallbackWrapper.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueTbMsgCallbackWrapper.java
index e812628f16..b3bd05ca5e 100644
--- a/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueTbMsgCallbackWrapper.java
+++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/MultipleTbQueueTbMsgCallbackWrapper.java
@@ -41,6 +41,6 @@ public class MultipleTbQueueTbMsgCallbackWrapper implements TbQueueCallback {
@Override
public void onFailure(Throwable t) {
- tbMsgCallback.onFailure(new RuleEngineException(t.getMessage()));
+ tbMsgCallback.onFailure(new RuleEngineException(t.getMessage(), t));
}
}
diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/TbQueueTbMsgCallbackWrapper.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/TbQueueTbMsgCallbackWrapper.java
index 413ef11e30..1107115085 100644
--- a/common/queue/src/main/java/org/thingsboard/server/queue/common/TbQueueTbMsgCallbackWrapper.java
+++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/TbQueueTbMsgCallbackWrapper.java
@@ -35,6 +35,6 @@ public class TbQueueTbMsgCallbackWrapper implements TbQueueCallback {
@Override
public void onFailure(Throwable t) {
- tbMsgCallback.onFailure(new RuleEngineException(t.getMessage()));
+ tbMsgCallback.onFailure(new RuleEngineException(t.getMessage(), t));
}
}
diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java
index fcf80bcf3d..e99817de17 100644
--- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java
+++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.queue.discovery;
import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.ProtocolStringList;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
@@ -44,8 +45,10 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -66,6 +69,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi
private Integer zkSessionTimeout;
@Value("${zk.zk_dir}")
private String zkDir;
+ @Value("${zk.recalculate_delay:0}")
+ private Long recalculateDelay;
+
+ protected final ConcurrentHashMap> delayedTasks;
private final TbServiceInfoProvider serviceInfoProvider;
private final PartitionService partitionService;
@@ -82,6 +89,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi
PartitionService partitionService) {
this.serviceInfoProvider = serviceInfoProvider;
this.partitionService = partitionService;
+ delayedTasks = new ConcurrentHashMap<>();
}
@PostConstruct
@@ -287,11 +295,39 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi
log.error("Failed to decode server instance for node {}", data.getPath(), e);
throw e;
}
- log.debug("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), instance.getServiceId());
+
+ String serviceId = instance.getServiceId();
+ ProtocolStringList serviceTypesList = instance.getServiceTypesList();
+
+ log.trace("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), serviceId);
switch (pathChildrenCacheEvent.getType()) {
case CHILD_ADDED:
+ ScheduledFuture> task = delayedTasks.remove(serviceId);
+ if (task != null) {
+ if (task.cancel(false)) {
+ log.debug("[{}] Recalculate partitions ignored. Service was restarted in time [{}].",
+ serviceId, serviceTypesList);
+ } else {
+ log.debug("[{}] Going to recalculate partitions. Service was not restarted in time [{}]!",
+ serviceId, serviceTypesList);
+ recalculatePartitions();
+ }
+ } else {
+ log.trace("[{}] Going to recalculate partitions due to adding new node [{}].",
+ serviceId, serviceTypesList);
+ recalculatePartitions();
+ }
+ break;
case CHILD_REMOVED:
- recalculatePartitions();
+ ScheduledFuture> future = zkExecutorService.schedule(() -> {
+ log.debug("[{}] Going to recalculate partitions due to removed node [{}]",
+ serviceId, serviceTypesList);
+ ScheduledFuture> removedTask = delayedTasks.remove(serviceId);
+ if (removedTask != null) {
+ recalculatePartitions();
+ }
+ }, recalculateDelay, TimeUnit.MILLISECONDS);
+ delayedTasks.put(serviceId, future);
break;
default:
break;
@@ -303,6 +339,8 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi
* Synchronized to ensure that other servers info is up to date
* */
synchronized void recalculatePartitions() {
+ delayedTasks.values().forEach(future -> future.cancel(false));
+ delayedTasks.clear();
partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers());
}
diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java
index 15c2f04d17..850f5c08ea 100644
--- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java
+++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java
@@ -30,6 +30,9 @@ import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsg;
import org.thingsboard.server.queue.TbQueueProducer;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -53,10 +56,14 @@ public class TbKafkaProducerTemplate implements TbQueuePro
private final Set topics;
+ @Getter
+ private final String clientId;
+
@Builder
private TbKafkaProducerTemplate(TbKafkaSettings settings, String defaultTopic, String clientId, TbQueueAdmin admin) {
Properties props = settings.toProducerProps();
+ this.clientId = Objects.requireNonNull(clientId, "Kafka producer client.id is null");
if (!StringUtils.isEmpty(clientId)) {
props.put(ProducerConfig.CLIENT_ID_CONFIG, clientId);
}
@@ -72,6 +79,22 @@ public class TbKafkaProducerTemplate implements TbQueuePro
public void init() {
}
+ void addAnalyticHeaders(List headers) {
+ headers.add(new RecordHeader("_producerId", getClientId().getBytes(StandardCharsets.UTF_8)));
+ headers.add(new RecordHeader("_threadName", Thread.currentThread().getName().getBytes(StandardCharsets.UTF_8)));
+ if (log.isTraceEnabled()) {
+ try {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ int maxlevel = Math.min(stackTrace.length, 10);
+ for (int i = 2; i < maxlevel; i++) { // ignore two levels: getStackTrace and addAnalyticHeaders
+ headers.add(new RecordHeader("_stackTrace" + i, stackTrace[i].toString().getBytes(StandardCharsets.UTF_8)));
+ }
+ } catch (Throwable t) {
+ log.trace("Failed to add stacktrace headers in Kafka producer {}", getClientId(), t);
+ }
+ }
+ }
+
@Override
public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) {
try {
@@ -79,7 +102,10 @@ public class TbKafkaProducerTemplate implements TbQueuePro
String key = msg.getKey().toString();
byte[] data = msg.getData();
ProducerRecord record;
- Iterable headers = msg.getHeaders().getData().entrySet().stream().map(e -> new RecordHeader(e.getKey(), e.getValue())).collect(Collectors.toList());
+ List headers = msg.getHeaders().getData().entrySet().stream().map(e -> new RecordHeader(e.getKey(), e.getValue())).collect(Collectors.toList());
+ if (log.isDebugEnabled()) {
+ addAnalyticHeaders(headers);
+ }
record = new ProducerRecord<>(tpi.getFullTopicName(), null, key, data, headers);
producer.send(record, (metadata, exception) -> {
if (exception == null) {
diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java
new file mode 100644
index 0000000000..a8810efd0e
--- /dev/null
+++ b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java
@@ -0,0 +1,189 @@
+/**
+ * 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.queue.discovery;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.imps.CuratorFrameworkState;
+import org.apache.curator.framework.recipes.cache.ChildData;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.thingsboard.common.util.ThingsBoardThreadFactory;
+import org.thingsboard.server.gen.transport.TransportProtos;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_ADDED;
+import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_REMOVED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ZkDiscoveryServiceTest {
+
+ @Mock
+ private TbServiceInfoProvider serviceInfoProvider;
+
+ @Mock
+ private PartitionService partitionService;
+
+ @Mock
+ private CuratorFramework client;
+
+ @Mock
+ private PathChildrenCache cache;
+
+ @Mock
+ private CuratorFramework curatorFramework;
+
+ private ZkDiscoveryService zkDiscoveryService;
+
+ private static final long RECALCULATE_DELAY = 100L;
+
+ final TransportProtos.ServiceInfo currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-0").build();
+ final ChildData currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray());
+ final TransportProtos.ServiceInfo childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-1").build();
+ final ChildData childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray());
+
+ @Before
+ public void setup() {
+ zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(serviceInfoProvider, partitionService));
+ ScheduledExecutorService zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery"));
+ when(client.getState()).thenReturn(CuratorFrameworkState.STARTED);
+ ReflectionTestUtils.setField(zkDiscoveryService, "stopped", false);
+ ReflectionTestUtils.setField(zkDiscoveryService, "client", client);
+ ReflectionTestUtils.setField(zkDiscoveryService, "cache", cache);
+ ReflectionTestUtils.setField(zkDiscoveryService, "nodePath", "/thingsboard/nodes/0000000010");
+ ReflectionTestUtils.setField(zkDiscoveryService, "zkExecutorService", zkExecutorService);
+ ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", RECALCULATE_DELAY);
+ ReflectionTestUtils.setField(zkDiscoveryService, "zkDir", "/thingsboard");
+
+ when(serviceInfoProvider.getServiceInfo()).thenReturn(currentInfo);
+
+ List dataList = new ArrayList<>();
+ dataList.add(currentData);
+ when(cache.getCurrentData()).thenReturn(dataList);
+ }
+
+ @Test
+ public void restartNodeInTimeTest() throws Exception {
+ startNode(childData);
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo)));
+
+ reset(partitionService);
+
+ stopNode(childData);
+
+ assertEquals(1, zkDiscoveryService.delayedTasks.size());
+
+ verify(partitionService, never()).recalculatePartitions(any(), any());
+
+ startNode(childData);
+
+ verify(partitionService, never()).recalculatePartitions(any(), any());
+
+ Thread.sleep(RECALCULATE_DELAY * 2);
+
+ verify(partitionService, never()).recalculatePartitions(any(), any());
+
+ assertTrue(zkDiscoveryService.delayedTasks.isEmpty());
+ }
+
+ @Test
+ public void restartNodeNotInTimeTest() throws Exception {
+ startNode(childData);
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo)));
+
+ reset(partitionService);
+
+ stopNode(childData);
+
+ assertEquals(1, zkDiscoveryService.delayedTasks.size());
+
+ Thread.sleep(RECALCULATE_DELAY * 2);
+
+ assertTrue(zkDiscoveryService.delayedTasks.isEmpty());
+
+ startNode(childData);
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(Collections.emptyList()));
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo)));
+
+ reset(partitionService);
+ }
+
+ @Test
+ public void startAnotherNodeDuringRestartTest() throws Exception {
+ var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-transport").build();
+ var anotherData = new ChildData("/thingsboard/nodes/0000000030", null, anotherInfo.toByteArray());
+
+ startNode(childData);
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo)));
+
+ reset(partitionService);
+
+ stopNode(childData);
+
+ assertEquals(1, zkDiscoveryService.delayedTasks.size());
+
+ startNode(anotherData);
+
+ assertTrue(zkDiscoveryService.delayedTasks.isEmpty());
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo)));
+ reset(partitionService);
+
+ Thread.sleep(RECALCULATE_DELAY * 2);
+
+ verify(partitionService, never()).recalculatePartitions(any(), any());
+
+ startNode(childData);
+
+ verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo, childInfo)));
+ }
+
+ private void startNode(ChildData data) throws Exception {
+ cache.getCurrentData().add(data);
+ zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_ADDED, data));
+ }
+
+ private void stopNode(ChildData data) throws Exception {
+ cache.getCurrentData().remove(data);
+ zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_REMOVED, data));
+ }
+
+}
diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java
new file mode 100644
index 0000000000..bfd3c4a6dc
--- /dev/null
+++ b/common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java
@@ -0,0 +1,54 @@
+/**
+ * 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.queue.kafka;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.common.header.Header;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.thingsboard.server.queue.TbQueueMsg;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.willCallRealMethod;
+import static org.mockito.BDDMockito.willReturn;
+import static org.mockito.Mockito.mock;
+
+@Slf4j
+class TbKafkaProducerTemplateTest {
+
+ TbKafkaProducerTemplate producerTemplate;
+
+ @BeforeEach
+ void setUp() {
+ producerTemplate = mock(TbKafkaProducerTemplate.class);
+ willCallRealMethod().given(producerTemplate).addAnalyticHeaders(any());
+ willReturn("tb-core-to-core-notifications-tb-core-3").given(producerTemplate).getClientId();
+ }
+
+ @Test
+ void testAddAnalyticHeaders() {
+ List headers = new ArrayList<>();
+ producerTemplate.addAnalyticHeaders(headers);
+ assertThat(headers).isNotEmpty();
+ headers.forEach(r -> log.info("RecordHeader key [{}] value [{}]", r.key(), new String(r.value(), StandardCharsets.UTF_8)));
+ }
+
+}
diff --git a/common/queue/src/test/resources/logback-test.xml b/common/queue/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..f7053313d4
--- /dev/null
+++ b/common/queue/src/test/resources/logback-test.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java
index bbf441a659..2a60980f84 100644
--- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java
+++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java
@@ -66,8 +66,6 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem
protected final Map scriptIdToHash = new ConcurrentHashMap<>();
protected final Map scriptMap = new ConcurrentHashMap<>();
- private final String tbelSwitch = "switch";
- private final String tbelSwitchErrorMsg = "TBEL does not support the 'switch'.";
protected Cache compiledScriptsCache;
private SandboxedParserConfiguration parserConfig;
@@ -183,11 +181,6 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem
lock.unlock();
}
return scriptId;
- } catch (CompileException ce) {
- if ( ce.getExpr() != null && new String(ce.getExpr()).contains(tbelSwitch)) {
- ce = new CompileException(tbelSwitchErrorMsg, ce.getExpr(), ce.getCursor(), ce.getCause());
- }
- throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, ce);
} catch (Exception e) {
throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e);
}
diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
index b337612011..bffd60f029 100644
--- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
+++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
@@ -57,6 +57,8 @@ public class TbUtils {
List.class)));
parserConfig.addImport("decodeToJson", new MethodStub(TbUtils.class.getMethod("decodeToJson",
ExecutionContext.class, List.class)));
+ parserConfig.addImport("decodeToJson", new MethodStub(TbUtils.class.getMethod("decodeToJson",
+ ExecutionContext.class, String.class)));
parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes",
ExecutionContext.class, String.class)));
parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes",
@@ -174,6 +176,9 @@ public class TbUtils {
public static Object decodeToJson(ExecutionContext ctx, List bytesList) throws IOException {
return TbJson.parse(ctx, bytesToString(bytesList));
}
+ public static Object decodeToJson(ExecutionContext ctx, String jsonStr) throws IOException {
+ return TbJson.parse(ctx, jsonStr);
+ }
public static String bytesToString(List bytesList) {
byte[] bytes = bytesFromList(bytesList);
diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
index b6d5395af8..a16a70b962 100644
--- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
+++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
@@ -27,6 +27,7 @@ import org.mvel2.SandboxedParserConfiguration;
import org.mvel2.execution.ExecutionArrayList;
import org.mvel2.execution.ExecutionHashMap;
+import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -348,6 +349,24 @@ public class TbUtilsTest {
Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false)));
}
+ @Test
+ public void parseBytesDecodeToJson() throws IOException {
+ String expectedStr = "{\"hello\": \"world\"}";
+ ExecutionHashMap expectedJson = new ExecutionHashMap<>(1, ctx);
+ expectedJson.put("hello", "world");
+ List expectedBytes = TbUtils.stringToBytes(ctx, expectedStr);
+ Object actualJson = TbUtils.decodeToJson(ctx, expectedBytes);
+ Assert.assertEquals(expectedJson,actualJson);
+ }
+ @Test
+ public void parseStringDecodeToJson() throws IOException {
+ String expectedStr = "{\"hello\": \"world\"}";
+ ExecutionHashMap expectedJson = new ExecutionHashMap<>(1, ctx);
+ expectedJson.put("hello", "world");
+ Object actualJson = TbUtils.decodeToJson(ctx, expectedStr);
+ Assert.assertEquals(expectedJson,actualJson);
+ }
+
private static List toList(byte[] data) {
List result = new ArrayList<>(data.length);
for (Byte b : data) {
diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapSessionMsgType.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapSessionMsgType.java
new file mode 100644
index 0000000000..fcf33ea037
--- /dev/null
+++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapSessionMsgType.java
@@ -0,0 +1,31 @@
+/**
+ * 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.transport.coap;
+
+public enum CoapSessionMsgType {
+
+ GET_ATTRIBUTES_REQUEST,
+ POST_ATTRIBUTES_REQUEST,
+ SUBSCRIBE_ATTRIBUTES_REQUEST,
+ UNSUBSCRIBE_ATTRIBUTES_REQUEST,
+ POST_TELEMETRY_REQUEST,
+ SUBSCRIBE_RPC_COMMANDS_REQUEST,
+ UNSUBSCRIBE_RPC_COMMANDS_REQUEST,
+ TO_DEVICE_RPC_RESPONSE,
+ TO_SERVER_RPC_REQUEST,
+ CLAIM_REQUEST;
+
+}
diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
index 7dde25bfd0..bd02d9fcc4 100644
--- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
+++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
@@ -30,10 +30,10 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
+import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.session.FeatureType;
-import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
@@ -120,7 +120,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
} else if (exchange.getRequestOptions().hasObserve()) {
processExchangeGetRequest(exchange, featureType.get());
} else if (featureType.get() == FeatureType.ATTRIBUTES) {
- processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST);
+ processRequest(exchange, CoapSessionMsgType.GET_ATTRIBUTES_REQUEST);
} else {
log.trace("Invalid feature type parameter");
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
@@ -129,13 +129,13 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
private void processExchangeGetRequest(CoapExchange exchange, FeatureType featureType) {
boolean unsubscribe = exchange.getRequestOptions().getObserve() == 1;
- SessionMsgType sessionMsgType;
+ CoapSessionMsgType coapSessionMsgType;
if (featureType == FeatureType.RPC) {
- sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST;
+ coapSessionMsgType = unsubscribe ? CoapSessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST : CoapSessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST;
} else {
- sessionMsgType = unsubscribe ? SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST;
+ coapSessionMsgType = unsubscribe ? CoapSessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST : CoapSessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST;
}
- processRequest(exchange, sessionMsgType);
+ processRequest(exchange, coapSessionMsgType);
}
@Override
@@ -147,21 +147,21 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
} else {
switch (featureType.get()) {
case ATTRIBUTES:
- processRequest(exchange, SessionMsgType.POST_ATTRIBUTES_REQUEST);
+ processRequest(exchange, CoapSessionMsgType.POST_ATTRIBUTES_REQUEST);
break;
case TELEMETRY:
- processRequest(exchange, SessionMsgType.POST_TELEMETRY_REQUEST);
+ processRequest(exchange, CoapSessionMsgType.POST_TELEMETRY_REQUEST);
break;
case RPC:
Optional requestId = getRequestId(exchange.advanced().getRequest());
if (requestId.isPresent()) {
- processRequest(exchange, SessionMsgType.TO_DEVICE_RPC_RESPONSE);
+ processRequest(exchange, CoapSessionMsgType.TO_DEVICE_RPC_RESPONSE);
} else {
- processRequest(exchange, SessionMsgType.TO_SERVER_RPC_REQUEST);
+ processRequest(exchange, CoapSessionMsgType.TO_SERVER_RPC_REQUEST);
}
break;
case CLAIM:
- processRequest(exchange, SessionMsgType.CLAIM_REQUEST);
+ processRequest(exchange, CoapSessionMsgType.CLAIM_REQUEST);
break;
case PROVISION:
processProvision(exchange);
@@ -195,7 +195,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
- private void processRequest(CoapExchange exchange, SessionMsgType type) {
+ private void processRequest(CoapExchange exchange, CoapSessionMsgType type) {
log.trace("Processing {}", exchange.advanced().getRequest());
deferAccept(exchange);
Exchange advanced = exchange.advanced();
@@ -218,7 +218,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
- private void processAccessTokenRequest(CoapExchange exchange, SessionMsgType type, Request request) {
+ private void processAccessTokenRequest(CoapExchange exchange, CoapSessionMsgType type, Request request) {
Optional credentials = decodeCredentials(request);
if (credentials.isEmpty()) {
exchange.respond(CoAP.ResponseCode.UNAUTHORIZED);
@@ -228,7 +228,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
new CoapDeviceAuthCallback(exchange, (deviceCredentials, deviceProfile) -> processRequest(exchange, type, request, deviceCredentials, deviceProfile)));
}
- private void processRequest(CoapExchange exchange, SessionMsgType type, Request request, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) {
+ private void processRequest(CoapExchange exchange, CoapSessionMsgType type, Request request, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) {
TbCoapClientState clientState = null;
try {
clientState = clients.getOrCreateClient(type, deviceCredentials, deviceProfile);
@@ -380,12 +380,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
- private Optional getFeatureType(Request request) {
+ protected Optional getFeatureType(Request request) {
List uriPath = request.getOptions().getUriPath();
try {
- if (uriPath.size() >= FEATURE_TYPE_POSITION) {
+ int size = uriPath.size();
+ if (size >= FEATURE_TYPE_POSITION) {
+ if (size == FEATURE_TYPE_POSITION && StringUtils.isNumeric(uriPath.get(size - 1))) {
+ return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 2).toUpperCase()));
+ }
return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase()));
- } else if (uriPath.size() >= FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) {
+ } else if (size == FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) {
if (uriPath.contains(DataConstants.PROVISION)) {
return Optional.of(FeatureType.valueOf(DataConstants.PROVISION.toUpperCase()));
}
diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/CoapClientContext.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/CoapClientContext.java
index 36ef8472de..a8531a7fba 100644
--- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/CoapClientContext.java
+++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/CoapClientContext.java
@@ -18,7 +18,7 @@ package org.thingsboard.server.transport.coap.client;
import org.eclipse.californium.core.observe.ObserveRelation;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.thingsboard.server.common.data.DeviceProfile;
-import org.thingsboard.server.common.msg.session.SessionMsgType;
+import org.thingsboard.server.transport.coap.CoapSessionMsgType;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos;
@@ -33,7 +33,7 @@ public interface CoapClientContext {
AtomicInteger getNotificationCounterByToken(String token);
- TbCoapClientState getOrCreateClient(SessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException;
+ TbCoapClientState getOrCreateClient(CoapSessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException;
TransportProtos.SessionInfoProto getNewSyncSession(TbCoapClientState clientState);
diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java
index f70967b72d..26effe7058 100644
--- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java
+++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/DefaultCoapClientContext.java
@@ -45,7 +45,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.session.FeatureType;
-import org.thingsboard.server.common.msg.session.SessionMsgType;
+import org.thingsboard.server.transport.coap.CoapSessionMsgType;
import org.thingsboard.server.common.transport.DeviceDeletedEvent;
import org.thingsboard.server.common.transport.DeviceProfileUpdatedEvent;
import org.thingsboard.server.common.transport.DeviceUpdatedEvent;
@@ -388,7 +388,7 @@ public class DefaultCoapClientContext implements CoapClientContext {
}
@Override
- public TbCoapClientState getOrCreateClient(SessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException {
+ public TbCoapClientState getOrCreateClient(CoapSessionMsgType type, ValidateDeviceCredentialsResponse deviceCredentials, DeviceProfile deviceProfile) throws AdaptorException {
DeviceId deviceId = deviceCredentials.getDeviceInfo().getDeviceId();
TbCoapClientState state = getClientState(deviceId);
state.lock();
diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java
new file mode 100644
index 0000000000..c7f33e3694
--- /dev/null
+++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java
@@ -0,0 +1,161 @@
+/**
+ * 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.transport.coap;
+
+import org.eclipse.californium.core.coap.CoAP;
+import org.eclipse.californium.core.coap.OptionSet;
+import org.eclipse.californium.core.coap.Request;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.thingsboard.server.coapserver.CoapServerService;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.msg.session.FeatureType;
+import org.thingsboard.server.common.transport.TransportService;
+import org.thingsboard.server.queue.scheduler.SchedulerComponent;
+import org.thingsboard.server.transport.coap.client.CoapClientContext;
+
+import java.util.Random;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class CoapTransportResourceTest {
+
+ private static final String V1 = "v1";
+ private static final String API = "api";
+ private static final String TELEMETRY = "telemetry";
+ private static final String ATTRIBUTES = "attributes";
+ private static final String RPC = "rpc";
+ private static final String CLAIM = "claim";
+ private static final String PROVISION = "provision";
+ private static final String GET_ATTRIBUTES_URI_QUERY = "clientKeys=attribute1,attribute2&sharedKeys=shared1,shared2";
+
+ private static final Random RANDOM = new Random();
+
+ private static CoapTransportResource coapTransportResource;
+
+ @BeforeAll
+ static void setUp() {
+
+ var ctxMock = mock(CoapTransportContext.class);
+ var coapServerServiceMock = mock(CoapServerService.class);
+ var transportServiceMock = mock(TransportService.class);
+ var clientContextMock = mock(CoapClientContext.class);
+ var schedulerComponentMock = mock(SchedulerComponent.class);
+
+ when(ctxMock.getTransportService()).thenReturn(transportServiceMock);
+ when(ctxMock.getClientContext()).thenReturn(clientContextMock);
+ when(ctxMock.getSessionReportTimeout()).thenReturn(1L);
+ when(ctxMock.getScheduler()).thenReturn(schedulerComponentMock);
+
+ coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1);
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideRequestAndFeatureType")
+ void givenRequest_whenGetFeatureType_thenReturnedExpectedFeatureType(Request request, FeatureType expectedFeatureType) {
+ var featureTypeOptional = coapTransportResource.getFeatureType(request);
+
+ assertTrue(featureTypeOptional.isPresent(), "Optional is empty");
+ assertEquals(expectedFeatureType, featureTypeOptional.get(), "Feature type is invalid");
+ }
+
+ static Stream provideRequestAndFeatureType() {
+ return Stream.of(
+ // accessToken based tests
+ Arguments.of(toAccessTokenRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY),
+ Arguments.of(toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES),
+ Arguments.of(toGetAttributesAccessTokenRequest(), FeatureType.ATTRIBUTES),
+ Arguments.of(toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES),
+ Arguments.of(toAccessTokenRequest(CoAP.Code.GET, RPC), FeatureType.RPC),
+ Arguments.of(toRpcResponseAccessTokenRequest(), FeatureType.RPC),
+ Arguments.of(toAccessTokenRequest(CoAP.Code.POST, RPC), FeatureType.RPC),
+ Arguments.of(toAccessTokenRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM),
+ // certificate based tests
+ Arguments.of(toCertificateRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY),
+ Arguments.of(toCertificateRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES),
+ Arguments.of(toGetAttributesCertificateRequest(), FeatureType.ATTRIBUTES),
+ Arguments.of(toCertificateRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES),
+ Arguments.of(toCertificateRequest(CoAP.Code.GET, RPC), FeatureType.RPC),
+ Arguments.of(toRpcResponseCertificateRequest(), FeatureType.RPC),
+ Arguments.of(toCertificateRequest(CoAP.Code.POST, RPC), FeatureType.RPC),
+ Arguments.of(toCertificateRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM),
+ // provision request
+ Arguments.of(toProvisionRequest(), FeatureType.PROVISION)
+ );
+ }
+
+ private static Request toAccessTokenRequest(CoAP.Code method, String featureType) {
+ return getAccessTokenRequest(method, featureType, null, null);
+ }
+
+ private static Request toGetAttributesAccessTokenRequest() {
+ return getAccessTokenRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY);
+ }
+
+ private static Request toRpcResponseAccessTokenRequest() {
+ return getAccessTokenRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null);
+ }
+
+ private static Request toCertificateRequest(CoAP.Code method, String featureType) {
+ return getCertificateRequest(method, featureType, null, null);
+ }
+
+ private static Request toGetAttributesCertificateRequest() {
+ return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY);
+ }
+
+ private static Request toRpcResponseCertificateRequest() {
+ return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null);
+ }
+
+ private static Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) {
+ return getRequest(method, featureType, false, requestId, uriQuery);
+ }
+
+ private static Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) {
+ return getRequest(method, featureType, true, requestId, uriQuery);
+ }
+
+ private static Request toProvisionRequest() {
+ return getRequest(CoAP.Code.POST, PROVISION, true, null, null);
+ }
+
+ private static Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) {
+ var request = new Request(method);
+ var options = new OptionSet();
+ options.addUriPath(API);
+ options.addUriPath(V1);
+ if (!dtls) {
+ options.addUriPath(StringUtils.randomAlphanumeric(20));
+ }
+ options.addUriPath(featureType);
+ if (requestId != null) {
+ options.addUriPath(String.valueOf(requestId));
+ }
+ if (uriQuery != null) {
+ options.setUriQuery(uriQuery);
+ }
+ request.setOptions(options);
+ return request;
+ }
+
+}
diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java
index 302bd20c8b..eef9a53024 100644
--- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java
+++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java
@@ -52,7 +52,7 @@ import java.util.stream.Collectors;
public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService {
@Autowired
- private TbLwM2MModelConfigStore modelStore;
+ TbLwM2MModelConfigStore modelStore;
@Autowired
@Lazy
@@ -67,14 +67,14 @@ public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService {
@Autowired
private LwM2MTelemetryLogService logService;
- private ConcurrentMap currentModelConfigs;
+ ConcurrentMap currentModelConfigs;
@AfterStartUp(order = AfterStartUp.BEFORE_TRANSPORT_SERVICE)
- private void init() {
+ public void init() {
List models = modelStore.getAll();
log.debug("Fetched model configs: {}", models);
currentModelConfigs = models.stream()
- .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m));
+ .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m, (existing, replacement) -> existing));
}
@Override
diff --git a/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java b/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java
new file mode 100644
index 0000000000..fc54ca9e0b
--- /dev/null
+++ b/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.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.transport.lwm2m.server.model;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MModelConfigStore;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.willReturn;
+import static org.mockito.Mockito.mock;
+
+class LwM2MModelConfigServiceImplTest {
+
+ LwM2MModelConfigServiceImpl service;
+ TbLwM2MModelConfigStore modelStore;
+
+ @BeforeEach
+ void setUp() {
+ service = new LwM2MModelConfigServiceImpl();
+ modelStore = mock(TbLwM2MModelConfigStore.class);
+ service.modelStore = modelStore;
+ }
+
+ @Test
+ void testInitWithDuplicatedModels() {
+ LwM2MModelConfig config = new LwM2MModelConfig("urn:imei:951358811362976");
+ List models = List.of(config, config);
+ willReturn(models).given(modelStore).getAll();
+ service.init();
+ assertThat(service.currentModelConfigs).containsExactlyEntriesOf(Map.of(config.getEndpoint(), config));
+ }
+
+ @Test
+ void testInitWithNonUniqueEndpoints() {
+ LwM2MModelConfig configAlfa = new LwM2MModelConfig("urn:imei:951358811362976");
+ LwM2MModelConfig configBravo = new LwM2MModelConfig("urn:imei:151358811362976");
+ LwM2MModelConfig configDelta = new LwM2MModelConfig("urn:imei:151358811362976");
+ assertThat(configBravo.getEndpoint()).as("non-unique endpoints provided").isEqualTo(configDelta.getEndpoint());
+ List models = List.of(configAlfa, configBravo, configDelta);
+ willReturn(models).given(modelStore).getAll();
+ service.init();
+ assertThat(service.currentModelConfigs).containsExactlyInAnyOrderEntriesOf(Map.of(
+ configAlfa.getEndpoint(), configAlfa,
+ configBravo.getEndpoint(), configBravo
+ ));
+ }
+
+ @Test
+ void testInitWithEmptyModels() {
+ willReturn(Collections.emptyList()).given(modelStore).getAll();
+ service.init();
+ assertThat(service.currentModelConfigs).isEmpty();
+ }
+
+}
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
index 95603e751c..5cd6ba9145 100644
--- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
@@ -71,6 +71,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
+import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE;
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED;
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN;
import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG;
@@ -85,7 +86,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMess
@Slf4j
public abstract class AbstractGatewaySessionHandler {
- protected static final String DEFAULT_DEVICE_TYPE = "default";
private static final String CAN_T_PARSE_VALUE = "Can't parse value: ";
private static final String DEVICE_PROPERTY = "device";
diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
index 3b827edbae..497540ee44 100644
--- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
+++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
@@ -49,14 +49,14 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.limit.LimitedApi;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
-import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
-import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import org.thingsboard.server.common.stats.MessagesStats;
import org.thingsboard.server.common.stats.StatsFactory;
@@ -583,7 +583,7 @@ public class DefaultTransportService implements TransportService {
metaData.putValue("deviceType", sessionInfo.getDeviceType());
metaData.putValue("ts", tsKv.getTs() + "");
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
- sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, SessionMsgType.POST_TELEMETRY_REQUEST, packCallback);
+ sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, TbMsgType.POST_TELEMETRY_REQUEST, packCallback);
}
}
}
@@ -603,7 +603,7 @@ public class DefaultTransportService implements TransportService {
}
metaData.putValue(DataConstants.NOTIFY_DEVICE_METADATA_KEY, "false");
CustomerId customerId = getCustomerId(sessionInfo);
- sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, SessionMsgType.POST_ATTRIBUTES_REQUEST,
+ sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, TbMsgType.POST_ATTRIBUTES_REQUEST,
new TransportTbQueueCallback(new ApiStatsProxyCallback<>(tenantId, customerId, msg.getKvList().size(), callback)));
}
}
@@ -723,7 +723,7 @@ public class DefaultTransportService implements TransportService {
metaData.putValue("serviceId", serviceInfoProvider.getServiceId());
metaData.putValue("sessionId", sessionId.toString());
sendToRuleEngine(tenantId, deviceId, getCustomerId(sessionInfo), sessionInfo, json, metaData,
- SessionMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback));
+ TbMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback));
String requestId = sessionId + "-" + msg.getRequestId();
toServerRpcPendingMap.put(requestId, new RpcRequestMetadata(sessionId, msg.getRequestId()));
scheduler.schedule(() -> processTimeout(requestId), clientSideRpcTimeout, TimeUnit.MILLISECONDS);
@@ -1136,7 +1136,7 @@ public class DefaultTransportService implements TransportService {
}
private void sendToRuleEngine(TenantId tenantId, DeviceId deviceId, CustomerId customerId, TransportProtos.SessionInfoProto sessionInfo, JsonObject json,
- TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) {
+ TbMsgMetaData metaData, TbMsgType tbMsgType, TbQueueCallback callback) {
DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
RuleChainId ruleChainId;
@@ -1151,7 +1151,7 @@ public class DefaultTransportService implements TransportService {
queueName = deviceProfile.getDefaultQueueName();
}
- TbMsg tbMsg = TbMsg.newMsg(queueName, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null);
+ TbMsg tbMsg = TbMsg.newMsg(queueName, tbMsgType, deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null);
sendToRuleEngine(tenantId, tbMsg, callback);
}
diff --git a/common/util/src/main/java/org/thingsboard/common/util/ExceptionUtil.java b/common/util/src/main/java/org/thingsboard/common/util/ExceptionUtil.java
new file mode 100644
index 0000000000..2ec15f3724
--- /dev/null
+++ b/common/util/src/main/java/org/thingsboard/common/util/ExceptionUtil.java
@@ -0,0 +1,67 @@
+/**
+ * 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.common.util;
+
+import com.google.gson.JsonParseException;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.id.EntityId;
+
+import javax.script.ScriptException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@Slf4j
+public class ExceptionUtil {
+
+ @SuppressWarnings("unchecked")
+ public static T lookupException(Throwable source, Class clazz) {
+ Exception e = lookupExceptionInCause(source, clazz);
+ if (e != null) {
+ return (T) e;
+ } else {
+ return null;
+ }
+ }
+
+ public static Exception lookupExceptionInCause(Throwable source, Class extends Exception>... clazzes) {
+ while (source != null) {
+ for (Class extends Exception> clazz : clazzes) {
+ if (clazz.isAssignableFrom(source.getClass())) {
+ return (Exception) source;
+ }
+ }
+ source = source.getCause();
+ }
+ return null;
+ }
+
+ public static String toString(Exception e, EntityId componentId, boolean stackTraceEnabled) {
+ Exception exception = lookupExceptionInCause(e, ScriptException.class, JsonParseException.class);
+ if (exception != null && StringUtils.isNotEmpty(exception.getMessage())) {
+ return exception.getMessage();
+ } else {
+ if (stackTraceEnabled) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ return sw.toString();
+ } else {
+ log.debug("[{}] Unknown error during message processing", componentId, e);
+ return "Please contact system administrator";
+ }
+ }
+ }
+}
diff --git a/common/util/src/test/java/org/thingsboard/common/util/ExceptionUtilTest.java b/common/util/src/test/java/org/thingsboard/common/util/ExceptionUtilTest.java
new file mode 100644
index 0000000000..e589ae8e30
--- /dev/null
+++ b/common/util/src/test/java/org/thingsboard/common/util/ExceptionUtilTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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.common.util;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ExceptionUtilTest {
+
+ final Exception cause = new RuntimeException();
+
+ @Test
+ void givenRootCause_whenLookupExceptionInCause_thenReturnRootCauseAndNoStackOverflow() {
+ Exception e = cause;
+ for (int i = 0; i <= 16384; i++) {
+ e = new Exception(e);
+ }
+ assertThat(ExceptionUtil.lookupExceptionInCause(e, RuntimeException.class)).isSameAs(cause);
+ }
+
+ @Test
+ void givenCause_whenLookupExceptionInCause_thenReturnCause() {
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(cause), RuntimeException.class)).isSameAs(cause);
+ }
+
+ @Test
+ void givenNoCauseAndExceptionIsWantedCauseClass_whenLookupExceptionInCause_thenReturnSelf() {
+ assertThat(ExceptionUtil.lookupExceptionInCause(cause, RuntimeException.class)).isSameAs(cause);
+ }
+
+ @Test
+ void givenNoCause_whenLookupExceptionInCause_thenReturnNull() {
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(), RuntimeException.class)).isNull();
+ }
+
+ @Test
+ void givenNotWantedCause_whenLookupExceptionInCause_thenReturnNull() {
+ final Exception cause = new IOException();
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(cause), RuntimeException.class)).isNull();
+ }
+
+ @Test
+ void givenCause_whenLookupExceptionInCauseByMany_thenReturnFirstCause() {
+ final Exception causeIAE = new IllegalAccessException();
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE))).isNull();
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), IOException.class, NoSuchFieldException.class)).isNull();
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), IllegalAccessException.class, IOException.class, NoSuchFieldException.class)).isSameAs(causeIAE);
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), IOException.class, NoSuchFieldException.class, IllegalAccessException.class)).isSameAs(causeIAE);
+
+ final Exception causeIOE = new IOException(causeIAE);
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE))).isNull();
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), ClassNotFoundException.class, NoSuchFieldException.class)).isNull();
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE), IOException.class, NoSuchFieldException.class)).isSameAs(causeIOE);
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE), IllegalAccessException.class, IOException.class, NoSuchFieldException.class)).isSameAs(causeIOE);
+ assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE), IOException.class, NoSuchFieldException.class, IllegalAccessException.class)).isSameAs(causeIOE);
+ }
+
+}
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..85428e14a9 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
@@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest;
import org.thingsboard.server.common.data.alarm.EntityAlarm;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
@@ -56,6 +57,9 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entity.EntityService;
+import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.ConstraintValidator;
import org.thingsboard.server.dao.service.DataValidator;
@@ -90,7 +94,12 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
@Override
public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) {
validateAlarmRequest(request);
- return withPropagated(alarmDao.updateAlarm(request));
+ AlarmApiCallResult result = withPropagated(alarmDao.updateAlarm(request));
+ if (result.getAlarm() != null) {
+ eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getAlarm().getTenantId()).entity(result)
+ .entityId(result.getAlarm().getId()).build());
+ }
+ return result;
}
@Override
@@ -112,17 +121,31 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
if (!result.isSuccessful() && !alarmCreationEnabled) {
throw new ApiUsageLimitsExceededException("Alarms creation is disabled");
}
+ if (result.getAlarm() != null) {
+ eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getAlarm().getTenantId())
+ .entityId(result.getAlarm().getId()).added(true).build());
+ }
return withPropagated(result);
}
@Override
public AlarmApiCallResult acknowledgeAlarm(TenantId tenantId, AlarmId alarmId, long ackTs) {
- return withPropagated(alarmDao.acknowledgeAlarm(tenantId, alarmId, ackTs));
+ var result = withPropagated(alarmDao.acknowledgeAlarm(tenantId, alarmId, ackTs));
+ if (result.getAlarm() != null) {
+ eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId())
+ .actionType(ActionType.ALARM_ACK).build());
+ }
+ return result;
}
@Override
public AlarmApiCallResult clearAlarm(TenantId tenantId, AlarmId alarmId, long clearTs, JsonNode details) {
- return withPropagated(alarmDao.clearAlarm(tenantId, alarmId, clearTs, details));
+ var result = withPropagated(alarmDao.clearAlarm(tenantId, alarmId, clearTs, details));
+ if (result.getAlarm() != null) {
+ eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId())
+ .actionType(ActionType.ALARM_CLEAR).build());
+ }
+ return result;
}
@Override
@@ -188,6 +211,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
} else {
deleteEntityRelations(tenantId, alarm.getId());
alarmDao.removeById(tenantId, alarm.getUuidId());
+ eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId)
+ .entityId(alarmId).entity(alarm).build());
return AlarmApiCallResult.builder().alarm(alarm).deleted(true).successful(true).build();
}
}
@@ -300,12 +325,22 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
@Override
public AlarmApiCallResult assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTime) {
- return withPropagated(alarmDao.assignAlarm(tenantId, alarmId, assigneeId, assignTime));
+ var result = withPropagated(alarmDao.assignAlarm(tenantId, alarmId, assigneeId, assignTime));
+ if (result.getAlarm() != null) {
+ eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId())
+ .actionType(ActionType.ALARM_ASSIGNED).build());
+ }
+ return result;
}
@Override
public AlarmApiCallResult unassignAlarm(TenantId tenantId, AlarmId alarmId, long unassignTime) {
- return withPropagated(alarmDao.unassignAlarm(tenantId, alarmId, unassignTime));
+ var result = withPropagated(alarmDao.unassignAlarm(tenantId, alarmId, unassignTime));
+ if (result.getAlarm() != null) {
+ eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId())
+ .actionType(ActionType.ALARM_UNASSIGNED).build());
+ }
+ return result;
}
@Override
diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java
index eb297e0049..b3bc89c34d 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java
@@ -33,6 +33,8 @@ 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.entity.AbstractCachedEntityService;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -118,6 +120,8 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService kvEntries) {
- kvEntries.forEach(AttributeUtils::validate);
+ public static void validate(List kvEntries, boolean valueNoXssValidation) {
+ kvEntries.forEach(tsKvEntry -> validate(tsKvEntry, valueNoXssValidation));
}
- public static void validate(AttributeKvEntry kvEntry) {
- KvUtils.validate(kvEntry);
+ public static void validate(AttributeKvEntry kvEntry, boolean valueNoXssValidation) {
+ KvUtils.validate(kvEntry, valueNoXssValidation);
if (kvEntry.getDataType() == null) {
throw new IncorrectParameterException("Incorrect kvEntry. Data type can't be null");
} else {
diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java
index 09414ac750..f855c116e2 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.attributes;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@@ -45,6 +46,9 @@ import static org.thingsboard.server.dao.attributes.AttributeUtils.validate;
public class BaseAttributesService implements AttributesService {
private final AttributesDao attributesDao;
+ @Value("${sql.attributes.value_no_xss_validation:false}")
+ private boolean valueNoXssValidation;
+
public BaseAttributesService(AttributesDao attributesDao) {
this.attributesDao = attributesDao;
}
@@ -82,14 +86,14 @@ public class BaseAttributesService implements AttributesService {
@Override
public ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) {
validate(entityId, scope);
- AttributeUtils.validate(attribute);
+ AttributeUtils.validate(attribute, valueNoXssValidation);
return attributesDao.save(tenantId, entityId, scope, attribute);
}
@Override
public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) {
validate(entityId, scope);
- AttributeUtils.validate(attributes);
+ AttributeUtils.validate(attributes, valueNoXssValidation);
List> saveFutures = attributes.stream().map(attribute -> attributesDao.save(tenantId, entityId, scope, attribute)).collect(Collectors.toList());
return Futures.allAsList(saveFutures);
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java
index b95ce39d9a..faff81670b 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java
@@ -69,6 +69,8 @@ public class CachedAttributesService implements AttributesService {
@Value("${cache.type:caffeine}")
private String cacheType;
+ @Value("${sql.attributes.value_no_xss_validation:false}")
+ private boolean valueNoXssValidation;
public CachedAttributesService(AttributesDao attributesDao,
StatsFactory statsFactory,
@@ -212,7 +214,7 @@ public class CachedAttributesService implements AttributesService {
@Override
public ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) {
validate(entityId, scope);
- AttributeUtils.validate(attribute);
+ AttributeUtils.validate(attribute, valueNoXssValidation);
ListenableFuture future = attributesDao.save(tenantId, entityId, scope, attribute);
return Futures.transform(future, key -> evict(entityId, scope, attribute, key), cacheExecutor);
}
@@ -220,7 +222,7 @@ public class CachedAttributesService implements AttributesService {
@Override
public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) {
validate(entityId, scope);
- AttributeUtils.validate(attributes);
+ AttributeUtils.validate(attributes, valueNoXssValidation);
List> futures = new ArrayList<>(attributes.size());
for (var attribute : attributes) {
diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
index 1d8704f0e6..e69ec5865c 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
@@ -15,7 +15,6 @@
*/
package org.thingsboard.server.dao.customer;
-import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -36,6 +35,8 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entity.EntityCountService;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -43,7 +44,6 @@ import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
import org.thingsboard.server.dao.user.UserService;
-import java.io.IOException;
import java.util.Optional;
import static org.thingsboard.server.dao.service.Validator.validateId;
@@ -112,6 +112,8 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
if (customer.getId() == null) {
countService.publishCountEntityEvictEvent(savedCustomer.getTenantId(), EntityType.CUSTOMER);
}
+ eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedCustomer.getTenantId())
+ .entityId(savedCustomer.getId()).added(customer.getId() == null).build());
return savedCustomer;
} catch (Exception e) {
checkConstraintViolation(e, "customer_external_id_unq_key", "Customer with such external id already exists!");
@@ -139,6 +141,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
apiUsageStateService.deleteApiUsageStateByEntityId(customerId);
customerDao.removeById(tenantId, customerId.getId());
countService.publishCountEntityEvictEvent(tenantId, EntityType.CUSTOMER);
+ eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(customerId).build());
}
@Override
diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
index 31fc29dd69..9abb86a7e8 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
@@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
@@ -45,6 +46,9 @@ import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.edge.EdgeDao;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entity.EntityCountService;
+import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -140,6 +144,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
try {
var saved = dashboardDao.save(dashboard.getTenantId(), dashboard);
publishEvictEvent(new DashboardTitleEvictEvent(saved.getId()));
+ eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(saved.getTenantId())
+ .entityId(saved.getId()).added(dashboard.getId() == null).build());
if (dashboard.getId() == null) {
countService.publishCountEntityEvictEvent(saved.getTenantId(), EntityType.DASHBOARD);
}
@@ -215,6 +221,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
dashboardDao.removeById(tenantId, dashboardId.getId());
publishEvictEvent(new DashboardTitleEvictEvent(dashboardId));
countService.publishCountEntityEvictEvent(tenantId, EntityType.DASHBOARD);
+ eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(dashboardId).build());
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_dashboard_device_profile")) {
@@ -304,6 +311,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
log.warn("[{}] Failed to create dashboard relation. Edge Id: [{}]", dashboardId, edgeId);
throw new RuntimeException(e);
}
+ eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).edgeId(edgeId).entityId(dashboardId)
+ .actionType(ActionType.ASSIGNED_TO_EDGE).build());
return dashboard;
}
@@ -320,6 +329,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
log.warn("[{}] Failed to delete dashboard relation. Edge Id: [{}]", dashboardId, edgeId);
throw new RuntimeException(e);
}
+ eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).edgeId(edgeId).entityId(dashboardId)
+ .actionType(ActionType.UNASSIGNED_FROM_EDGE).build());
return dashboard;
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java
new file mode 100644
index 0000000000..033aa4e0bc
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java
@@ -0,0 +1,34 @@
+/**
+ * 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.device;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Map;
+
+@Configuration
+@ConfigurationProperties(prefix = "device")
+@Data
+public class DeviceConnectivityConfiguration {
+ private Map connectivity;
+
+ public boolean isEnabled(String protocol) {
+ var info = connectivity.get(protocol);
+ return info != null && info.isEnabled();
+ }
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java
new file mode 100644
index 0000000000..b243be9995
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java
@@ -0,0 +1,26 @@
+/**
+ * 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.device;
+
+import lombok.Data;
+
+@Data
+public class DeviceConnectivityInfo {
+ private boolean enabled;
+ private String host;
+ private String port;
+ private String pemCertFile;
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java
new file mode 100644
index 0000000000..c06103d8f3
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java
@@ -0,0 +1,268 @@
+/**
+ * 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.device;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Service;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.DeviceProfile;
+import org.thingsboard.server.common.data.DeviceTransportType;
+import org.thingsboard.server.common.data.ResourceUtils;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
+import org.thingsboard.server.common.data.id.DeviceId;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.common.data.security.DeviceCredentialsType;
+import org.thingsboard.server.dao.util.DeviceConnectivityUtil;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.thingsboard.server.dao.service.Validator.validateId;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CHECK_DOCUMENTATION;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT;
+import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS;
+
+@Service("DeviceConnectivityDaoService")
+@Slf4j
+public class DeviceConnectivityServiceImpl implements DeviceConnectivityService {
+
+ public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
+ public static final String INCORRECT_DEVICE_ID = "Incorrect deviceId ";
+ public static final String DEFAULT_DEVICE_TELEMETRY_TOPIC = "v1/devices/me/telemetry";
+
+ @Autowired
+ private DeviceCredentialsService deviceCredentialsService;
+
+ @Autowired
+ private DeviceProfileService deviceProfileService;
+
+ @Autowired
+ private DeviceConnectivityConfiguration deviceConnectivityConfiguration;
+
+ @Override
+ public JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException {
+ DeviceId deviceId = device.getId();
+ log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId);
+ validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
+
+ DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId);
+ DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
+ DeviceTransportType transportType = deviceProfile.getTransportType();
+
+ ObjectNode commands = JacksonUtil.newObjectNode();
+ switch (transportType) {
+ case DEFAULT:
+ Optional.ofNullable(getHttpTransportPublishCommands(baseUrl, creds))
+ .ifPresent(v -> commands.set(HTTP, v));
+ Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, creds))
+ .ifPresent(v -> commands.set(MQTT, v));
+ Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds))
+ .ifPresent(v -> commands.set(COAP, v));
+ break;
+ case MQTT:
+ MqttDeviceProfileTransportConfiguration transportConfiguration =
+ (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
+ //TODO: add sparkplug command with emulator (check SSL)
+ if (transportConfiguration.isSparkplug()) {
+ ObjectNode sparkplug = JacksonUtil.newObjectNode();
+ sparkplug.put("sparkplug", CHECK_DOCUMENTATION);
+ commands.set(MQTT, sparkplug);
+ } else {
+ String topicName = transportConfiguration.getDeviceTelemetryTopic();
+
+ Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, topicName, creds))
+ .ifPresent(v -> commands.set(MQTT, v));
+ }
+ break;
+ case COAP:
+ Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds))
+ .ifPresent(v -> commands.set(COAP, v));
+ break;
+ default:
+ commands.put(transportType.name(), CHECK_DOCUMENTATION);
+ }
+ return commands;
+ }
+
+ @Override
+ public Resource getPemCertFile(String protocol) {
+ String certFilePath = deviceConnectivityConfiguration.getConnectivity()
+ .get(protocol)
+ .getPemCertFile();
+
+ if (StringUtils.isNotBlank(certFilePath) && ResourceUtils.resourceExists(this, certFilePath)) {
+ return new ClassPathResource(certFilePath);
+ } else {
+ return null;
+ }
+ }
+
+ private JsonNode getHttpTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ ObjectNode httpCommands = JacksonUtil.newObjectNode();
+ Optional.ofNullable(getHttpPublishCommand(HTTP, defaultHostname, deviceCredentials))
+ .ifPresent(v -> httpCommands.put(HTTP, v));
+ Optional.ofNullable(getHttpPublishCommand(HTTPS, defaultHostname, deviceCredentials))
+ .ifPresent(v -> httpCommands.put(HTTPS, v));
+ return httpCommands.isEmpty() ? null : httpCommands;
+ }
+
+ private String getHttpPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol);
+ if (properties == null || !properties.isEnabled() ||
+ deviceCredentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) {
+ return null;
+ }
+ String hostName = getHost(baseUrl, properties);
+ String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort();
+
+ return DeviceConnectivityUtil.getHttpPublishCommand(protocol, hostName, port, deviceCredentials);
+ }
+
+ private JsonNode getMqttTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ return getMqttTransportPublishCommands(baseUrl, DEFAULT_DEVICE_TELEMETRY_TOPIC, deviceCredentials);
+ }
+
+ private JsonNode getMqttTransportPublishCommands(String baseUrl, String topic, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ ObjectNode mqttCommands = JacksonUtil.newObjectNode();
+
+ if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) {
+ mqttCommands.put(MQTTS, CHECK_DOCUMENTATION);
+ return mqttCommands;
+ }
+
+ ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode();
+
+ if (deviceConnectivityConfiguration.isEnabled(MQTT)) {
+ Optional.ofNullable(getMqttPublishCommand(baseUrl, topic, deviceCredentials)).
+ ifPresent(v -> mqttCommands.put(MQTT, v));
+
+ Optional.ofNullable(getDockerMqttPublishCommand(MQTT, baseUrl, topic, deviceCredentials))
+ .ifPresent(v -> dockerMqttCommands.put(MQTT, v));
+ }
+
+ if (deviceConnectivityConfiguration.isEnabled(MQTTS)) {
+ List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials);
+ if (mqttsPublishCommand != null) {
+ ArrayNode arrayNode = mqttCommands.putArray(MQTTS);
+ mqttsPublishCommand.forEach(arrayNode::add);
+ }
+
+ Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, baseUrl, topic, deviceCredentials))
+ .ifPresent(v -> dockerMqttCommands.put(MQTTS, v));
+ }
+
+ if (!dockerMqttCommands.isEmpty()) {
+ mqttCommands.set(DOCKER, dockerMqttCommands);
+ }
+ return mqttCommands.isEmpty() ? null : mqttCommands;
+ }
+
+ private String getMqttPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTT);
+ String mqttHost = getHost(baseUrl, properties);
+ String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort();
+ return DeviceConnectivityUtil.getMqttPublishCommand(MQTT, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials);
+ }
+
+ private List getMqttsPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTTS);
+ String mqttHost = getHost(baseUrl, properties);
+ String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort();
+ String pubCommand = DeviceConnectivityUtil.getMqttPublishCommand(MQTTS, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials);
+
+ ArrayList commands = new ArrayList<>();
+ if (pubCommand != null) {
+ commands.add(DeviceConnectivityUtil.getCurlPemCertCommand(baseUrl, MQTTS));
+ commands.add(pubCommand);
+ return commands;
+ }
+ return null;
+ }
+
+ private String getDockerMqttPublishCommand(String protocol, String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol);
+ String mqttHost = getHost(baseUrl, properties);
+ String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort();
+ return DeviceConnectivityUtil.getDockerMqttPublishCommand(protocol, baseUrl, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials);
+ }
+
+ private JsonNode getCoapTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ ObjectNode coapCommands = JacksonUtil.newObjectNode();
+
+ if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) {
+ coapCommands.put(COAPS, CHECK_DOCUMENTATION);
+ return coapCommands;
+ }
+
+ ObjectNode dockerCoapCommands = JacksonUtil.newObjectNode();
+
+ if (deviceConnectivityConfiguration.isEnabled(COAP)) {
+ Optional.ofNullable(getCoapPublishCommand(COAP, baseUrl, deviceCredentials))
+ .ifPresent(v -> coapCommands.put(COAP, v));
+
+ Optional.ofNullable(getDockerCoapPublishCommand(COAP, baseUrl, deviceCredentials))
+ .ifPresent(v -> dockerCoapCommands.put(COAP, v));
+ }
+
+ if (deviceConnectivityConfiguration.isEnabled(COAPS)) {
+ Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials))
+ .ifPresent(v -> coapCommands.put(COAPS, v));
+
+ Optional.ofNullable(getDockerCoapPublishCommand(COAPS, baseUrl, deviceCredentials))
+ .ifPresent(v -> dockerCoapCommands.put(COAPS, v));
+ }
+
+ if (!dockerCoapCommands.isEmpty()) {
+ coapCommands.set(DOCKER, dockerCoapCommands);
+ }
+
+ return coapCommands.isEmpty() ? null : coapCommands;
+ }
+
+ private String getCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol);
+ String hostName = getHost(baseUrl, properties);
+ String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort();
+ return DeviceConnectivityUtil.getCoapPublishCommand(protocol, hostName, port, deviceCredentials);
+ }
+
+ private String getDockerCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException {
+ DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol);
+ String host = getHost(baseUrl, properties);
+ String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort();
+ return DeviceConnectivityUtil.getDockerCoapPublishCommand(protocol, host, port, deviceCredentials);
+ }
+
+ private String getHost(String baseUrl, DeviceConnectivityInfo properties) throws URISyntaxException {
+ return properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost();
+ }
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java
index 6e79b953ff..0a8d1b65a9 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java
@@ -25,6 +25,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredential;
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials;
@@ -41,6 +42,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
+import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.dao.service.DataValidator;
@@ -107,6 +109,9 @@ public class DeviceCredentialsServiceImpl extends AbstractCachedEntityService sync = new ThreadLocal<>();
+
+ @Override
+ public boolean isSync() {
+ Boolean sync = this.sync.get();
+ return sync != null && sync;
+ }
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
index 31b446fbd5..127741e8d0 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeInfo;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
@@ -53,6 +54,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
+import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
@@ -179,6 +181,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService cache;
- @Autowired
- private ApplicationEventPublisher eventPublisher;
-
protected void publishEvictEvent(E event) {
if (TransactionSynchronizationManager.isActualTransactionActive()) {
eventPublisher.publishEvent(event);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
index 6d4ac9f97b..17cd7a15d4 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.entity;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.StringUtils;
@@ -43,6 +44,9 @@ public abstract class AbstractEntityService {
public static final String INCORRECT_EDGE_ID = "Incorrect edgeId ";
public static final String INCORRECT_PAGE_LINK = "Incorrect page link ";
+ @Autowired
+ protected ApplicationEventPublisher eventPublisher;
+
@Lazy
@Autowired
protected RelationService relationService;
@@ -113,7 +117,7 @@ public abstract class AbstractEntityService {
List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(tenantId, entityId);
if (entityViews != null && !entityViews.isEmpty()) {
EntityView entityView = entityViews.get(0);
- Boolean relationExists = relationService.checkRelation(
+ boolean relationExists = relationService.checkRelation(
tenantId, edgeId, entityView.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE
);
@@ -122,5 +126,4 @@ public abstract class AbstractEntityService {
}
}
}
-
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
index 6433db5ae8..2e5ee9071b 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
@@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.CustomerId;
@@ -43,6 +44,9 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
+import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -104,6 +108,8 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService {
+ private final TenantId tenantId;
+ private final EntityId entityId;
+ private final EdgeId edgeId;
+ private final T entity;
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java
new file mode 100644
index 0000000000..81437cd781
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java
@@ -0,0 +1,28 @@
+/**
+ * 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 lombok.Data;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.relation.EntityRelation;
+
+@Data
+public class RelationActionEvent {
+ private final TenantId tenantId;
+ private final EntityRelation relation;
+ private final ActionType actionType;
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java
new file mode 100644
index 0000000000..205f592d43
--- /dev/null
+++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java
@@ -0,0 +1,30 @@
+/**
+ * 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 lombok.Builder;
+import lombok.Data;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+
+@Builder
+@Data
+public class SaveEntityEvent {
+ private final TenantId tenantId;
+ private final T entity;
+ private final EntityId entityId;
+ private final Boolean added;
+}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java
index 425724bf2c..92289b7178 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java
@@ -19,13 +19,13 @@ import com.google.common.base.Function;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import org.thingsboard.common.util.ThingsBoardThreadFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.thingsboard.common.util.ThingsBoardExecutors;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
/**
* Created by ashvayka on 21.02.17.
@@ -34,9 +34,12 @@ public abstract class CassandraAbstractAsyncDao extends CassandraAbstractDao {
protected ExecutorService readResultsProcessingExecutor;
+ @Value("${cassandra.query.result_processing_threads:50}")
+ private int threadPoolSize;
+
@PostConstruct
public void startExecutor() {
- readResultsProcessingExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("cassandra-callback"));
+ readResultsProcessingExecutor = ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "cassandra-callback");
}
@PreDestroy
diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
index 2a784d7985..13f84161c8 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
@@ -38,6 +38,8 @@ import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -77,10 +79,12 @@ public class BaseOtaPackageService extends AbstractCachedEntityService handleEvictEvent(EntityRelationEvent.from(relation)), MoreExecutors.directExecutor());
+ future.addListener(() -> {
+ handleEvictEvent(EntityRelationEvent.from(relation));
+ eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_ADD_OR_UPDATE));
+ }, MoreExecutors.directExecutor());
return future;
}
@@ -188,6 +195,7 @@ public class BaseRelationService implements RelationService {
var result = relationDao.deleteRelation(tenantId, relation);
//TODO: evict cache only if the relation was deleted. Note: relationDao.deleteRelation requires improvement.
publishEvictEvent(EntityRelationEvent.from(relation));
+ eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_DELETED));
return result;
}
@@ -196,7 +204,10 @@ public class BaseRelationService implements RelationService {
log.trace("Executing deleteRelationAsync [{}]", relation);
validate(relation);
var future = relationDao.deleteRelationAsync(tenantId, relation);
- future.addListener(() -> handleEvictEvent(EntityRelationEvent.from(relation)), MoreExecutors.directExecutor());
+ future.addListener(() -> {
+ handleEvictEvent(EntityRelationEvent.from(relation));
+ eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_DELETED));
+ }, MoreExecutors.directExecutor());
return future;
}
@@ -206,7 +217,9 @@ public class BaseRelationService implements RelationService {
validate(from, to, relationType, typeGroup);
var result = relationDao.deleteRelation(tenantId, from, to, relationType, typeGroup);
//TODO: evict cache only if the relation was deleted. Note: relationDao.deleteRelation requires improvement.
- publishEvictEvent(new EntityRelationEvent(from, to, relationType, typeGroup));
+ EntityRelation entityRelation = new EntityRelation(from, to, relationType, typeGroup);
+ publishEvictEvent(EntityRelationEvent.from(entityRelation));
+ eventPublisher.publishEvent(new RelationActionEvent(tenantId, entityRelation, ActionType.RELATION_DELETED));
return result;
}
@@ -220,17 +233,36 @@ public class BaseRelationService implements RelationService {
return future;
}
+ @Transactional
+ @Override
+ public void deleteEntityCommonRelations(TenantId tenantId, EntityId entityId) {
+ deleteEntityRelations(tenantId, entityId, RelationTypeGroup.COMMON);
+ }
+
@Transactional
@Override
public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
+ deleteEntityRelations(tenantId, entityId, null);
+ }
+
+ @Transactional
+ public void deleteEntityRelations(TenantId tenantId, EntityId entityId, RelationTypeGroup relationTypeGroup) {
log.trace("Executing deleteEntityRelations [{}]", entityId);
validate(entityId);
- List inboundRelations = new ArrayList<>(relationDao.findAllByTo(tenantId, entityId));
- List outboundRelations = new ArrayList<>(relationDao.findAllByFrom(tenantId, entityId));
+ List