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 +165,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);
@@ -225,6 +209,12 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case RELATION:
future = relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg);
break;
+ case TENANT:
+ future = tenantEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
+ break;
+ case TENANT_PROFILE:
+ future = tenantProfileEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
+ break;
default:
log.warn("Edge event type [{}] is not designed to be pushed to edge", type);
future = Futures.immediateFuture(null);
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
index 474c7ba233..da63cb53d7 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
@@ -35,6 +35,8 @@ import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
+import org.thingsboard.server.dao.tenant.TenantProfileService;
+import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
@@ -55,6 +57,8 @@ import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgePr
import org.thingsboard.server.service.edge.rpc.processor.rule.RuleChainEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.settings.AdminSettingsEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.telemetry.TelemetryEdgeProcessor;
+import org.thingsboard.server.service.edge.rpc.processor.tenant.TenantEdgeProcessor;
+import org.thingsboard.server.service.edge.rpc.processor.tenant.TenantProfileEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.user.UserEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.widget.WidgetBundleEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.widget.WidgetTypeEdgeProcessor;
@@ -122,6 +126,12 @@ public class EdgeContextComponent {
@Autowired
private OtaPackageService otaPackageService;
+ @Autowired
+ private TenantService tenantService;
+
+ @Autowired
+ private TenantProfileService tenantProfileService;
+
@Autowired
private QueueService queueService;
@@ -179,6 +189,12 @@ public class EdgeContextComponent {
@Autowired
private QueueEdgeProcessor queueEdgeProcessor;
+ @Autowired
+ private TenantEdgeProcessor tenantEdgeProcessor;
+
+ @Autowired
+ private TenantProfileEdgeProcessor tenantProfileEdgeProcessor;
+
@Autowired
private EdgeMsgConstructor edgeMsgConstructor;
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 b7334ebf5a..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);
}
@@ -341,7 +338,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
sessionNewEvents.put(edgeId, false);
Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() {
@Override
- public void onSuccess(Void result) {
+ public void onSuccess(Boolean newEventsAdded) {
+ if (Boolean.TRUE.equals(newEventsAdded)) {
+ sessionNewEvents.put(edgeId, true);
+ }
scheduleEdgeEventsCheck(session);
}
@@ -395,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);
@@ -448,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 {
@@ -461,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/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
index 1dd0f31c20..d5d73d47e7 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
@@ -24,6 +24,7 @@ import io.grpc.stub.StreamObserver;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
+import org.springframework.data.util.Pair;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
@@ -35,13 +36,19 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.common.data.page.SortOrder;
+import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.AttributesRequestMsg;
import org.thingsboard.server.gen.edge.v1.ConnectRequestMsg;
import org.thingsboard.server.gen.edge.v1.ConnectResponseCode;
import org.thingsboard.server.gen.edge.v1.ConnectResponseMsg;
+import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.DeviceCredentialsUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceRpcCallMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@@ -50,6 +57,7 @@ import org.thingsboard.server.gen.edge.v1.EdgeConfiguration;
import org.thingsboard.server.gen.edge.v1.EdgeUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.EntityDataProto;
+import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EntityViewsRequestMsg;
import org.thingsboard.server.gen.edge.v1.RelationRequestMsg;
import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg;
@@ -68,17 +76,15 @@ import org.thingsboard.server.service.edge.rpc.fetch.GeneralEdgeEventFetcher;
import java.io.Closeable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
@Slf4j
@Data
@@ -89,6 +95,7 @@ public final class EdgeGrpcSession implements Closeable {
private static final int MAX_DOWNLINK_ATTEMPTS = 10; // max number of attemps to send downlink message if edge connected
private static final String QUEUE_START_TS_ATTR_KEY = "queueStartTs";
+ private static final String QUEUE_START_SEQ_ID_ATTR_KEY = "queueStartSeqId";
private final UUID sessionId;
private final BiConsumer sessionOpenListener;
@@ -103,6 +110,12 @@ public final class EdgeGrpcSession implements Closeable {
private boolean connected;
private boolean syncCompleted;
+ private Long newStartTs;
+ private Long previousStartTs;
+ private Long newStartSeqId;
+ private Long previousStartSeqId;
+ private Long seqIdEnd;
+
private EdgeVersion edgeVersion;
private int maxInboundMessageSize;
@@ -143,8 +156,8 @@ public final class EdgeGrpcSession implements Closeable {
}
if (connected) {
if (requestMsg.getMsgType().equals(RequestMsgType.SYNC_REQUEST_RPC_MESSAGE)) {
- if (requestMsg.hasSyncRequestMsg() && requestMsg.getSyncRequestMsg().getSyncRequired()) {
- boolean fullSync = true;
+ if (requestMsg.hasSyncRequestMsg()) {
+ boolean fullSync = false;
if (requestMsg.getSyncRequestMsg().hasFullSync()) {
fullSync = requestMsg.getSyncRequestMsg().getFullSync();
}
@@ -204,10 +217,10 @@ public final class EdgeGrpcSession implements Closeable {
EdgeEventFetcher next = cursor.getNext();
log.info("[{}][{}] starting sync process, cursor current idx = {}, class = {}",
edge.getTenantId(), edge.getId(), cursor.getCurrentIdx(), next.getClass().getSimpleName());
- ListenableFuture uuidListenableFuture = startProcessingEdgeEvents(next);
- Futures.addCallback(uuidListenableFuture, new FutureCallback<>() {
+ ListenableFuture> future = startProcessingEdgeEvents(next);
+ Futures.addCallback(future, new FutureCallback<>() {
@Override
- public void onSuccess(@Nullable UUID result) {
+ public void onSuccess(@Nullable Pair result) {
doSync(cursor);
}
@@ -307,36 +320,51 @@ public final class EdgeGrpcSession implements Closeable {
sendDownlinkMsg(edgeConfigMsg);
}
- ListenableFuture processEdgeEvents() throws Exception {
- SettableFuture result = SettableFuture.create();
+ ListenableFuture processEdgeEvents() throws Exception {
+ SettableFuture result = SettableFuture.create();
log.trace("[{}] starting processing edge events", this.sessionId);
if (isConnected() && isSyncCompleted()) {
- Long queueStartTs = getQueueStartTs().get();
+ Pair startTsAndSeqId = getQueueStartTsAndSeqId().get();
+ this.previousStartTs = startTsAndSeqId.getFirst();
+ this.previousStartSeqId = startTsAndSeqId.getSecond();
GeneralEdgeEventFetcher fetcher = new GeneralEdgeEventFetcher(
- queueStartTs,
+ this.previousStartTs,
+ this.previousStartSeqId,
+ this.seqIdEnd,
+ false,
+ Integer.toUnsignedLong(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount()),
ctx.getEdgeEventService());
- ListenableFuture ifOffsetFuture = startProcessingEdgeEvents(fetcher);
- Futures.addCallback(ifOffsetFuture, new FutureCallback<>() {
+ Futures.addCallback(startProcessingEdgeEvents(fetcher), new FutureCallback<>() {
@Override
- public void onSuccess(@Nullable UUID ifOffset) {
- if (ifOffset != null) {
- Long newStartTs = Uuids.unixTimestamp(ifOffset);
- ListenableFuture> updateFuture = updateQueueStartTs(newStartTs);
+ public void onSuccess(@Nullable Pair newStartTsAndSeqId) {
+ if (newStartTsAndSeqId != null) {
+ ListenableFuture> updateFuture = updateQueueStartTsAndSeqId(newStartTsAndSeqId);
Futures.addCallback(updateFuture, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List list) {
- log.debug("[{}] queue offset was updated [{}][{}]", sessionId, ifOffset, newStartTs);
- result.set(null);
+ log.debug("[{}] queue offset was updated [{}]", sessionId, newStartTsAndSeqId);
+ if (fetcher.isSeqIdNewCycleStarted()) {
+ seqIdEnd = fetcher.getSeqIdEnd();
+ boolean newEventsAvailable = isNewEdgeEventsAvailable();
+ result.set(newEventsAvailable);
+ } else {
+ seqIdEnd = null;
+ boolean newEventsAvailable = isSeqIdStartedNewCycle();
+ if (!newEventsAvailable) {
+ newEventsAvailable = isNewEdgeEventsAvailable();
+ }
+ result.set(newEventsAvailable);
+ }
}
@Override
public void onFailure(Throwable t) {
- log.error("[{}] Failed to update queue offset [{}]", sessionId, ifOffset, t);
+ log.error("[{}] Failed to update queue offset [{}]", sessionId, newStartTsAndSeqId, t);
result.setException(t);
}
}, ctx.getGrpcCallbackExecutorService());
} else {
- log.trace("[{}] ifOffset is null. Skipping iteration without db update", sessionId);
+ log.trace("[{}] newStartTsAndSeqId is null. Skipping iteration without db update", sessionId);
result.set(null);
}
}
@@ -354,14 +382,14 @@ public final class EdgeGrpcSession implements Closeable {
return result;
}
- private ListenableFuture startProcessingEdgeEvents(EdgeEventFetcher fetcher) {
- SettableFuture result = SettableFuture.create();
+ private ListenableFuture> startProcessingEdgeEvents(EdgeEventFetcher fetcher) {
+ SettableFuture> result = SettableFuture.create();
PageLink pageLink = fetcher.getPageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount());
processEdgeEvents(fetcher, pageLink, result);
return result;
}
- private void processEdgeEvents(EdgeEventFetcher fetcher, PageLink pageLink, SettableFuture result) {
+ private void processEdgeEvents(EdgeEventFetcher fetcher, PageLink pageLink, SettableFuture> result) {
try {
PageData pageData = fetcher.fetchEdgeEvents(edge.getTenantId(), edge, pageLink);
if (isConnected() && !pageData.getData().isEmpty()) {
@@ -377,8 +405,15 @@ public final class EdgeGrpcSession implements Closeable {
if (isConnected() && pageData.hasNext()) {
processEdgeEvents(fetcher, pageLink.nextPageLink(), result);
} else {
- UUID ifOffset = pageData.getData().get(pageData.getData().size() - 1).getUuidId();
- result.set(ifOffset);
+ EdgeEvent latestEdgeEvent = pageData.getData().get(pageData.getData().size() - 1);
+ UUID idOffset = latestEdgeEvent.getUuidId();
+ if (idOffset != null) {
+ Long newStartTs = Uuids.unixTimestamp(idOffset);
+ long newStartSeqId = latestEdgeEvent.getSeqId();
+ result.set(Pair.of(newStartTs, newStartSeqId));
+ } else {
+ result.set(null);
+ }
}
}
}
@@ -461,69 +496,113 @@ public final class EdgeGrpcSession implements Closeable {
}
}
- private DownlinkMsg convertToDownlinkMsg(EdgeEvent edgeEvent) {
- log.trace("[{}][{}] converting edge event to downlink msg [{}]", edge.getTenantId(), this.sessionId, edgeEvent);
- DownlinkMsg downlinkMsg = null;
- try {
- switch (edgeEvent.getAction()) {
- case UPDATED:
- case ADDED:
- case DELETED:
- case ASSIGNED_TO_EDGE:
- case UNASSIGNED_FROM_EDGE:
- case ALARM_ACK:
- case ALARM_CLEAR:
- case CREDENTIALS_UPDATED:
- case RELATION_ADD_OR_UPDATE:
- case RELATION_DELETED:
- case ASSIGNED_TO_CUSTOMER:
- case UNASSIGNED_FROM_CUSTOMER:
- case CREDENTIALS_REQUEST:
- case RPC_CALL:
- downlinkMsg = convertEntityEventToDownlink(edgeEvent);
- log.trace("[{}][{}] entity message processed [{}]", edgeEvent.getTenantId(), this.sessionId, downlinkMsg);
- break;
- case ATTRIBUTES_UPDATED:
- case POST_ATTRIBUTES:
- case ATTRIBUTES_DELETED:
- case TIMESERIES_UPDATED:
- downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent);
- break;
- default:
- log.warn("[{}][{}] Unsupported action type [{}]", edge.getTenantId(), this.sessionId, edgeEvent.getAction());
+ private List convertToDownlinkMsgsPack(List edgeEvents) {
+ List result = new ArrayList<>();
+ for (EdgeEvent edgeEvent : edgeEvents) {
+ log.trace("[{}][{}] converting edge event to downlink msg [{}]", edge.getTenantId(), this.sessionId, edgeEvent);
+ DownlinkMsg downlinkMsg = null;
+ try {
+ switch (edgeEvent.getAction()) {
+ case UPDATED:
+ case ADDED:
+ case DELETED:
+ case ASSIGNED_TO_EDGE:
+ case UNASSIGNED_FROM_EDGE:
+ case ALARM_ACK:
+ case ALARM_CLEAR:
+ case CREDENTIALS_UPDATED:
+ case RELATION_ADD_OR_UPDATE:
+ case RELATION_DELETED:
+ case CREDENTIALS_REQUEST:
+ case RPC_CALL:
+ case ASSIGNED_TO_CUSTOMER:
+ case UNASSIGNED_FROM_CUSTOMER:
+ downlinkMsg = convertEntityEventToDownlink(edgeEvent);
+ log.trace("[{}][{}] entity message processed [{}]", edgeEvent.getTenantId(), this.sessionId, downlinkMsg);
+ break;
+ case ATTRIBUTES_UPDATED:
+ case POST_ATTRIBUTES:
+ case ATTRIBUTES_DELETED:
+ case TIMESERIES_UPDATED:
+ downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent);
+ break;
+ default:
+ log.warn("[{}][{}] Unsupported action type [{}]", edge.getTenantId(), this.sessionId, edgeEvent.getAction());
+ }
+ } catch (Exception e) {
+ log.error("[{}][{}] Exception during converting edge event to downlink msg", edge.getTenantId(), this.sessionId, e);
+ }
+ if (downlinkMsg != null) {
+ result.add(downlinkMsg);
+ }
+ }
+ return result;
+ }
+
+ private ListenableFuture> getQueueStartTsAndSeqId() {
+ ListenableFuture> future =
+ ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, Arrays.asList(QUEUE_START_TS_ATTR_KEY, QUEUE_START_SEQ_ID_ATTR_KEY));
+ return Futures.transform(future, attributeKvEntries -> {
+ long startTs = 0L;
+ long startSeqId = 0L;
+ for (AttributeKvEntry attributeKvEntry : attributeKvEntries) {
+ if (QUEUE_START_TS_ATTR_KEY.equals(attributeKvEntry.getKey())) {
+ startTs = attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L;
+ }
+ if (QUEUE_START_SEQ_ID_ATTR_KEY.equals(attributeKvEntry.getKey())) {
+ startSeqId = attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L;
+ }
+ }
+ if (startSeqId == 0L) {
+ startSeqId = findStartSeqIdFromOldestEventIfAny();
}
+ return Pair.of(startTs, startSeqId);
+ }, ctx.getGrpcCallbackExecutorService());
+ }
+
+ private boolean isSeqIdStartedNewCycle() {
+ try {
+ TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), 0, null, null, this.newStartTs, System.currentTimeMillis());
+ PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), 0L, this.previousStartSeqId == 0 ? null : this.previousStartSeqId - 1, pageLink);
+ return !edgeEvents.getData().isEmpty();
} catch (Exception e) {
- log.error("[{}][{}] Exception during converting edge event to downlink msg", edge.getTenantId(), this.sessionId, e);
+ log.error("[{}][{}][{}] Failed to execute isSeqIdStartedNewCycle", edge.getTenantId(), edge.getId(), sessionId, e);
}
- return downlinkMsg;
+ return false;
}
- private List convertToDownlinkMsgsPack(List edgeEvents) {
- return edgeEvents
- .stream()
- .map(this::convertToDownlinkMsg)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
+ private boolean isNewEdgeEventsAvailable() {
+ try {
+ TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), 0, null, null, this.newStartTs, System.currentTimeMillis());
+ PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), this.newStartSeqId, null, pageLink);
+ return !edgeEvents.getData().isEmpty();
+ } catch (Exception e) {
+ log.error("[{}][{}][{}] Failed to execute isNewEdgeEventsAvailable", edge.getTenantId(), edge.getId(), sessionId, e);
+ }
+ return false;
}
- private ListenableFuture getQueueStartTs() {
- ListenableFuture> future =
- ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, QUEUE_START_TS_ATTR_KEY);
- return Futures.transform(future, attributeKvEntryOpt -> {
- if (attributeKvEntryOpt != null && attributeKvEntryOpt.isPresent()) {
- AttributeKvEntry attributeKvEntry = attributeKvEntryOpt.get();
- return attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L;
- } else {
- return 0L;
+ private long findStartSeqIdFromOldestEventIfAny() {
+ long startSeqId = 0L;
+ try {
+ TimePageLink pageLink = new TimePageLink(1, 0, null, new SortOrder("createdTime"), null, null);
+ PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), null, null, pageLink);
+ if (!edgeEvents.getData().isEmpty()) {
+ startSeqId = edgeEvents.getData().get(0).getSeqId() - 1;
}
- }, ctx.getGrpcCallbackExecutorService());
+ } catch (Exception e) {
+ log.error("[{}][{}][{}] Failed to execute findStartSeqIdFromOldestEventIfAny", edge.getTenantId(), edge.getId(), sessionId, e);
+ }
+ return startSeqId;
}
- private ListenableFuture> updateQueueStartTs(Long newStartTs) {
- log.trace("[{}] updating QueueStartTs [{}][{}]", this.sessionId, edge.getId(), newStartTs);
- List attributes = Collections.singletonList(
- new BaseAttributeKvEntry(
- new LongDataEntry(QUEUE_START_TS_ATTR_KEY, newStartTs), System.currentTimeMillis()));
+ private ListenableFuture> updateQueueStartTsAndSeqId(Pair pair) {
+ this.newStartTs = pair.getFirst();
+ this.newStartSeqId = pair.getSecond();
+ log.trace("[{}] updateQueueStartTsAndSeqId [{}][{}][{}]", this.sessionId, edge.getId(), this.newStartTs, this.newStartSeqId);
+ List attributes = Arrays.asList(
+ new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_TS_ATTR_KEY, this.newStartTs), System.currentTimeMillis()),
+ new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_SEQ_ID_ATTR_KEY, this.newStartSeqId), System.currentTimeMillis()));
return ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes);
}
@@ -566,6 +645,10 @@ public final class EdgeGrpcSession implements Closeable {
return ctx.getOtaPackageEdgeProcessor().convertOtaPackageEventToDownlink(edgeEvent);
case QUEUE:
return ctx.getQueueEdgeProcessor().convertQueueEventToDownlink(edgeEvent);
+ case TENANT:
+ return ctx.getTenantEdgeProcessor().convertTenantEventToDownlink(edgeEvent);
+ case TENANT_PROFILE:
+ return ctx.getTenantProfileEdgeProcessor().convertTenantProfileEventToDownlink(edgeEvent);
default:
log.warn("Unsupported edge event type [{}]", edgeEvent);
return null;
@@ -580,6 +663,11 @@ public final class EdgeGrpcSession implements Closeable {
result.addAll(ctx.getTelemetryProcessor().processTelemetryMsg(edge.getTenantId(), entityData));
}
}
+ if (uplinkMsg.getDeviceProfileUpdateMsgCount() > 0) {
+ for (DeviceProfileUpdateMsg deviceProfileUpdateMsg : uplinkMsg.getDeviceProfileUpdateMsgList()) {
+ result.add(ctx.getDeviceProfileProcessor().processDeviceProfileMsgFromEdge(edge.getTenantId(), edge, deviceProfileUpdateMsg));
+ }
+ }
if (uplinkMsg.getDeviceUpdateMsgCount() > 0) {
for (DeviceUpdateMsg deviceUpdateMsg : uplinkMsg.getDeviceUpdateMsgList()) {
result.add(ctx.getDeviceProcessor().processDeviceMsgFromEdge(edge.getTenantId(), edge, deviceUpdateMsg));
@@ -590,16 +678,36 @@ public final class EdgeGrpcSession implements Closeable {
result.add(ctx.getDeviceProcessor().processDeviceCredentialsMsg(edge.getTenantId(), deviceCredentialsUpdateMsg));
}
}
+ if (uplinkMsg.getAssetProfileUpdateMsgCount() > 0) {
+ for (AssetProfileUpdateMsg assetProfileUpdateMsg : uplinkMsg.getAssetProfileUpdateMsgList()) {
+ result.add(ctx.getAssetProfileProcessor().processAssetProfileMsgFromEdge(edge.getTenantId(), edge, assetProfileUpdateMsg));
+ }
+ }
+ if (uplinkMsg.getAssetUpdateMsgCount() > 0) {
+ for (AssetUpdateMsg assetUpdateMsg : uplinkMsg.getAssetUpdateMsgList()) {
+ result.add(ctx.getAssetProcessor().processAssetMsgFromEdge(edge.getTenantId(), edge, assetUpdateMsg));
+ }
+ }
if (uplinkMsg.getAlarmUpdateMsgCount() > 0) {
for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdateMsgList()) {
result.add(ctx.getAlarmProcessor().processAlarmMsg(edge.getTenantId(), alarmUpdateMsg));
}
}
+ if (uplinkMsg.getEntityViewUpdateMsgCount() > 0) {
+ for (EntityViewUpdateMsg entityViewUpdateMsg : uplinkMsg.getEntityViewUpdateMsgList()) {
+ result.add(ctx.getEntityViewProcessor().processEntityViewMsgFromEdge(edge.getTenantId(), edge, entityViewUpdateMsg));
+ }
+ }
if (uplinkMsg.getRelationUpdateMsgCount() > 0) {
for (RelationUpdateMsg relationUpdateMsg : uplinkMsg.getRelationUpdateMsgList()) {
result.add(ctx.getRelationProcessor().processRelationMsg(edge.getTenantId(), relationUpdateMsg));
}
}
+ if (uplinkMsg.getDashboardUpdateMsgCount() > 0) {
+ for (DashboardUpdateMsg dashboardUpdateMsg : uplinkMsg.getDashboardUpdateMsgList()) {
+ result.add(ctx.getDashboardProcessor().processDashboardMsgFromEdge(edge.getTenantId(), edge, dashboardUpdateMsg));
+ }
+ }
if (uplinkMsg.getRuleChainMetadataRequestMsgCount() > 0) {
for (RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg : uplinkMsg.getRuleChainMetadataRequestMsgList()) {
result.add(ctx.getEdgeRequestsService().processRuleChainMetadataRequestMsg(edge.getTenantId(), edge, ruleChainMetadataRequestMsg));
@@ -693,8 +801,11 @@ public final class EdgeGrpcSession implements Closeable {
}
private void interruptPreviousSendDownlinkMsgsTask() {
- log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", edge.getTenantId(), edge.getId(), this.sessionId);
- stopCurrentSendDownlinkMsgsTask(true);
+ if (sessionState.getSendDownlinkMsgsFuture() != null && !sessionState.getSendDownlinkMsgsFuture().isDone()
+ || sessionState.getScheduledSendDownlinkTask() != null && !sessionState.getScheduledSendDownlinkTask().isCancelled()) {
+ log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", edge.getTenantId(), edge.getId(), this.sessionId);
+ stopCurrentSendDownlinkMsgsTask(true);
+ }
}
private void interruptGeneralProcessingOnSync() {
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
index bf3e804f7e..a74a0df18c 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
@@ -34,6 +34,7 @@ import org.thingsboard.server.service.edge.rpc.fetch.QueuesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.RuleChainsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.SystemWidgetsBundlesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.TenantAdminUsersEdgeEventFetcher;
+import org.thingsboard.server.service.edge.rpc.fetch.TenantEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.TenantWidgetsBundlesEdgeEventFetcher;
import java.util.LinkedList;
@@ -51,8 +52,7 @@ public class EdgeSyncCursor {
fetchers.add(new QueuesEdgeEventFetcher(ctx.getQueueService()));
fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService()));
fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), ctx.getFreemarkerConfig()));
- fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService()));
- fetchers.add(new AssetProfilesEdgeEventFetcher(ctx.getAssetProfileService()));
+ fetchers.add(new TenantEdgeEventFetcher(ctx.getTenantService()));
fetchers.add(new TenantAdminUsersEdgeEventFetcher(ctx.getUserService()));
Customer publicCustomer = ctx.getCustomerService().findOrCreatePublicCustomer(edge.getTenantId());
fetchers.add(new CustomerEdgeEventFetcher(publicCustomer.getId()));
@@ -61,6 +61,8 @@ public class EdgeSyncCursor {
fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId()));
}
}
+ fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService()));
+ fetchers.add(new AssetProfilesEdgeEventFetcher(ctx.getAssetProfileService()));
fetchers.add(new DevicesEdgeEventFetcher(ctx.getDeviceService()));
fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService()));
fetchers.add(new EntityViewsEdgeEventFetcher(ctx.getEntityViewService()));
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
index 69a83da0a0..447a73e5cf 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
@@ -18,7 +18,10 @@ package org.thingsboard.server.service.edge.rpc.constructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityViewId;
@@ -47,13 +50,22 @@ public class AlarmMsgConstructor {
String entityName = null;
switch (alarm.getOriginator().getEntityType()) {
case DEVICE:
- entityName = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId())).getName();
+ Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId()));
+ if (deviceById != null) {
+ entityName = deviceById.getName();
+ }
break;
case ASSET:
- entityName = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId())).getName();
+ Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId()));
+ if (assetById != null) {
+ entityName = assetById.getName();
+ }
break;
case ENTITY_VIEW:
- entityName = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId())).getName();
+ EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId()));
+ if (entityViewById != null) {
+ entityName = entityViewById.getName();
+ }
break;
}
AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder()
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantMsgConstructor.java
new file mode 100644
index 0000000000..321a57970a
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantMsgConstructor.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.server.service.edge.rpc.constructor;
+
+import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.gen.edge.v1.TenantUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+
+@Component
+@TbCoreComponent
+public class TenantMsgConstructor {
+
+ public TenantUpdateMsg constructTenantUpdateMsg(UpdateMsgType msgType, Tenant tenant) {
+ TenantUpdateMsg.Builder builder = TenantUpdateMsg.newBuilder()
+ .setMsgType(msgType)
+ .setIdMSB(tenant.getId().getId().getMostSignificantBits())
+ .setIdLSB(tenant.getId().getId().getLeastSignificantBits())
+ .setTitle(tenant.getTitle())
+ .setProfileIdMSB(tenant.getTenantProfileId().getId().getMostSignificantBits())
+ .setProfileIdLSB(tenant.getTenantProfileId().getId().getLeastSignificantBits())
+ .setRegion(tenant.getRegion());
+ if (tenant.getCountry() != null) {
+ builder.setCountry(tenant.getCountry());
+ }
+ if (tenant.getState() != null) {
+ builder.setState(tenant.getState());
+ }
+ if (tenant.getCity() != null) {
+ builder.setCity(tenant.getCity());
+ }
+ if (tenant.getAddress() != null) {
+ builder.setAddress(tenant.getAddress());
+ }
+ if (tenant.getAddress2() != null) {
+ builder.setAddress2(tenant.getAddress2());
+ }
+ if (tenant.getZip() != null) {
+ builder.setZip(tenant.getZip());
+ }
+ if (tenant.getPhone() != null) {
+ builder.setPhone(tenant.getPhone());
+ }
+ if (tenant.getEmail() != null) {
+ builder.setEmail(tenant.getEmail());
+ }
+ if (tenant.getAdditionalInfo() != null) {
+ builder.setAdditionalInfo(JacksonUtil.toString(tenant.getAdditionalInfo()));
+ }
+ return builder.build();
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantProfileMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantProfileMsgConstructor.java
new file mode 100644
index 0000000000..57655c3aeb
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantProfileMsgConstructor.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.constructor;
+
+import com.google.protobuf.ByteString;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.data.TenantProfile;
+import org.thingsboard.server.gen.edge.v1.TenantProfileUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
+import org.thingsboard.server.queue.util.DataDecodingEncodingService;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+
+@Component
+@TbCoreComponent
+public class TenantProfileMsgConstructor {
+
+ @Autowired
+ private DataDecodingEncodingService dataDecodingEncodingService;
+
+ public TenantProfileUpdateMsg constructTenantProfileUpdateMsg(UpdateMsgType msgType, TenantProfile tenantProfile) {
+ TenantProfileUpdateMsg.Builder builder = TenantProfileUpdateMsg.newBuilder()
+ .setMsgType(msgType)
+ .setIdMSB(tenantProfile.getId().getId().getMostSignificantBits())
+ .setIdLSB(tenantProfile.getId().getId().getLeastSignificantBits())
+ .setName(tenantProfile.getName())
+ .setDefault(tenantProfile.isDefault())
+ .setIsolatedRuleChain(tenantProfile.isIsolatedTbRuleEngine())
+ .setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(tenantProfile.getProfileData())));
+ if (tenantProfile.getDescription() != null) {
+ builder.setDescription(tenantProfile.getDescription());
+ }
+ return builder.build();
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java
index a574b8bb4b..b2b82a34d7 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java
@@ -36,8 +36,8 @@ public class WidgetTypeMsgConstructor {
if (widgetTypeDetails.getBundleAlias() != null) {
builder.setBundleAlias(widgetTypeDetails.getBundleAlias());
}
- if (widgetTypeDetails.getAlias() != null) {
- builder.setAlias(widgetTypeDetails.getAlias());
+ if (widgetTypeDetails.getFqn() != null) {
+ builder.setFqn(widgetTypeDetails.getFqn());
}
if (widgetTypeDetails.getName() != null) {
builder.setName(widgetTypeDetails.getName());
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java
index 327184e6a9..24008ece09 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java
@@ -16,19 +16,27 @@
package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
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.page.SortOrder;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.edge.EdgeEventService;
@AllArgsConstructor
+@Slf4j
public class GeneralEdgeEventFetcher implements EdgeEventFetcher {
private final Long queueStartTs;
+ private Long seqIdStart;
+ @Getter
+ private Long seqIdEnd;
+ @Getter
+ private boolean seqIdNewCycleStarted;
+ private Long maxReadRecordsCount;
private final EdgeEventService edgeEventService;
@Override
@@ -37,13 +45,32 @@ public class GeneralEdgeEventFetcher implements EdgeEventFetcher {
pageSize,
0,
null,
- new SortOrder("createdTime", SortOrder.Direction.ASC),
+ null,
queueStartTs,
- null);
+ System.currentTimeMillis());
}
@Override
public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) {
- return edgeEventService.findEdgeEvents(tenantId, edge.getId(), (TimePageLink) pageLink, true);
+ try {
+ PageData edgeEvents = edgeEventService.findEdgeEvents(tenantId, edge.getId(), seqIdStart, seqIdEnd, (TimePageLink) pageLink);
+ if (edgeEvents.getData().isEmpty()) {
+ this.seqIdEnd = Math.max(this.maxReadRecordsCount, seqIdStart - this.maxReadRecordsCount);
+ edgeEvents = edgeEventService.findEdgeEvents(tenantId, edge.getId(), 0L, seqIdEnd, (TimePageLink) pageLink);
+ if (edgeEvents.getData().stream().anyMatch(ee -> ee.getSeqId() < seqIdStart)) {
+ log.info("[{}] seqId column of edge_event table started new cycle [{}]", tenantId, edge.getId());
+ this.seqIdNewCycleStarted = true;
+ this.seqIdStart = 0L;
+ } else {
+ edgeEvents = new PageData<>();
+ log.warn("[{}] unexpected edge notification message received. " +
+ "no new events found and seqId column of edge_event table doesn't started new cycle [{}]", tenantId, edge.getId());
+ }
+ }
+ return edgeEvents;
+ } catch (Exception e) {
+ log.error("[{}] failed to find edge events [{}]", tenantId, edge.getId());
+ }
+ return new PageData<>();
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantEdgeEventFetcher.java
new file mode 100644
index 0000000000..1e9f81be0f
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantEdgeEventFetcher.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.fetch;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.dao.tenant.TenantService;
+
+import java.util.List;
+
+@AllArgsConstructor
+@Slf4j
+public class TenantEdgeEventFetcher extends BasePageableEdgeEventFetcher {
+
+ private final TenantService tenantService;
+
+ @Override
+ PageData fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) {
+ Tenant tenant = tenantService.findTenantById(tenantId);
+ // returns PageData object to be in sync with other fetchers
+ return new PageData<>(List.of(tenant), 1, 1, false);
+ }
+
+ @Override
+ EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Tenant entity) {
+ return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.TENANT,
+ EdgeEventActionType.UPDATED, entity.getId(), 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..239f72dcd6 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,10 +21,16 @@ 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.Dashboard;
import org.thingsboard.server.common.data.Device;
+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.EntityView;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -42,8 +48,11 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.common.data.relation.EntityRelation;
+import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.asset.AssetService;
@@ -55,12 +64,14 @@ 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;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator;
+import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
@@ -84,6 +95,8 @@ import org.thingsboard.server.service.edge.rpc.constructor.OtaPackageMsgConstruc
import org.thingsboard.server.service.edge.rpc.constructor.QueueMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RelationMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainMsgConstructor;
+import org.thingsboard.server.service.edge.rpc.constructor.TenantMsgConstructor;
+import org.thingsboard.server.service.edge.rpc.constructor.TenantProfileMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.UserMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.WidgetTypeMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.WidgetsBundleMsgConstructor;
@@ -104,6 +117,7 @@ import java.util.concurrent.locks.ReentrantLock;
public abstract class BaseEdgeProcessor {
protected static final Lock deviceCreationLock = new ReentrantLock();
+ protected static final Lock assetCreationLock = new ReentrantLock();
protected static final int DEFAULT_PAGE_SIZE = 100;
@@ -140,6 +154,9 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected TenantService tenantService;
+ @Autowired
+ protected TenantProfileService tenantProfileService;
+
@Autowired
protected EdgeService edgeService;
@@ -195,6 +212,21 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected DataValidator deviceValidator;
+ @Autowired
+ protected DataValidator deviceProfileValidator;
+
+ @Autowired
+ protected DataValidator assetValidator;
+
+ @Autowired
+ protected DataValidator assetProfileValidator;
+
+ @Autowired
+ protected DataValidator dashboardValidator;
+
+ @Autowired
+ protected DataValidator entityViewValidator;
+
@Autowired
protected EdgeMsgConstructor edgeMsgConstructor;
@@ -234,6 +266,12 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected AssetProfileMsgConstructor assetProfileMsgConstructor;
+ @Autowired
+ protected TenantMsgConstructor tenantMsgConstructor;
+
+ @Autowired
+ protected TenantProfileMsgConstructor tenantProfileMsgConstructor;
+
@Autowired
protected WidgetsBundleMsgConstructor widgetsBundleMsgConstructor;
@@ -249,15 +287,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 +329,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 +381,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 +432,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 +483,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:
@@ -508,4 +556,28 @@ public abstract class BaseEdgeProcessor {
return false;
}
}
+
+ protected void createRelationFromEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId) {
+ EntityRelation relation = new EntityRelation();
+ relation.setFrom(edgeId);
+ relation.setTo(entityId);
+ relation.setTypeGroup(RelationTypeGroup.COMMON);
+ relation.setType(EntityRelation.EDGE_TYPE);
+ relationService.saveRelation(tenantId, relation);
+ }
+
+ protected TbMsgMetaData getActionTbMsgMetaData(Edge edge, CustomerId customerId) {
+ TbMsgMetaData metaData = getTbMsgMetaData(edge);
+ if (customerId != null && !customerId.isNullUid()) {
+ metaData.putValue("customerId", customerId.toString());
+ }
+ return metaData;
+ }
+
+ protected TbMsgMetaData getTbMsgMetaData(Edge edge) {
+ TbMsgMetaData metaData = new TbMsgMetaData();
+ metaData.putValue("edgeId", edge.getId().toString());
+ metaData.putValue("edgeName", edge.getName());
+ return metaData;
+ }
}
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..3e61a538c5 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,26 +15,113 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.asset;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;
+import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.dao.asset.BaseAssetService;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
+import org.thingsboard.server.queue.TbQueueCallback;
+import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
-public class AssetEdgeProcessor extends BaseEdgeProcessor {
+public class AssetEdgeProcessor extends BaseAssetProcessor {
+
+ public ListenableFuture processAssetMsgFromEdge(TenantId tenantId, Edge edge, AssetUpdateMsg assetUpdateMsg) {
+ log.trace("[{}] executing processAssetMsgFromEdge [{}] from edge [{}]", tenantId, assetUpdateMsg, edge.getName());
+ AssetId assetId = new AssetId(new UUID(assetUpdateMsg.getIdMSB(), assetUpdateMsg.getIdLSB()));
+ try {
+ edgeSynchronizationManager.getSync().set(true);
+
+ switch (assetUpdateMsg.getMsgType()) {
+ case ENTITY_CREATED_RPC_MESSAGE:
+ case ENTITY_UPDATED_RPC_MESSAGE:
+ saveOrUpdateAsset(tenantId, assetId, assetUpdateMsg, edge);
+ return Futures.immediateFuture(null);
+ case ENTITY_DELETED_RPC_MESSAGE:
+ Asset assetToDelete = assetService.findAssetById(tenantId, assetId);
+ if (assetToDelete != null) {
+ assetService.unassignAssetFromEdge(tenantId, assetId, edge.getId());
+ }
+ return Futures.immediateFuture(null);
+ case UNRECOGNIZED:
+ default:
+ return handleUnsupportedMsgType(assetUpdateMsg.getMsgType());
+ }
+ } catch (DataValidationException e) {
+ if (e.getMessage().contains("limit reached")) {
+ log.warn("[{}] Number of allowed asset violated {}", tenantId, assetUpdateMsg, e);
+ return Futures.immediateFuture(null);
+ } else {
+ return Futures.immediateFailedFuture(e);
+ }
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
+
+ private void saveOrUpdateAsset(TenantId tenantId, AssetId assetId, AssetUpdateMsg assetUpdateMsg, Edge edge) {
+ CustomerId customerId = safeGetCustomerId(assetUpdateMsg.getCustomerIdMSB(), assetUpdateMsg.getCustomerIdLSB());
+ Pair resultPair = super.saveOrUpdateAsset(tenantId, assetId, assetUpdateMsg, customerId);
+ Boolean created = resultPair.getFirst();
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), assetId);
+ pushAssetCreatedEventToRuleEngine(tenantId, edge, assetId);
+ assetService.assignAssetToEdge(tenantId, assetId, edge.getId());
+ }
+ Boolean assetNameUpdated = resultPair.getSecond();
+ if (assetNameUpdated) {
+ saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET, EdgeEventActionType.UPDATED, assetId, null);
+ }
+ }
+
+ private void pushAssetCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetId assetId) {
+ try {
+ Asset asset = assetService.findAssetById(tenantId, assetId);
+ ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(asset);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, assetId, asset.getCustomerId(),
+ getActionTbMsgMetaData(edge, asset.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
+ tbClusterService.pushMsgToRuleEngine(tenantId, assetId, tbMsg, new TbQueueCallback() {
+ @Override
+ public void onSuccess(TbQueueMsgMetadata metadata) {
+ log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", asset);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", asset, t);
+ }
+ });
+ } catch (JsonProcessingException | IllegalArgumentException e) {
+ log.warn("[{}] Failed to push asset action to rule engine: {}", assetId, DataConstants.ENTITY_CREATED, e);
+ }
+ }
public DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent) {
AssetId assetId = new AssetId(edgeEvent.getEntityId());
@@ -46,7 +133,7 @@ public class AssetEdgeProcessor extends BaseEdgeProcessor {
case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER:
Asset asset = assetService.findAssetById(edgeEvent.getTenantId(), assetId);
- if (asset != null) {
+ if (asset != null && !BaseAssetService.TB_SERVICE_QUEUE.equals(asset.getType())) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
AssetUpdateMsg assetUpdateMsg =
assetMsgConstructor.constructAssetUpdatedMsg(msgType, asset);
@@ -72,8 +159,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..3cae9c5123 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,25 +15,91 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.asset;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.asset.AssetProfile;
+import org.thingsboard.server.common.data.edge.Edge;
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.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
+import org.thingsboard.server.queue.TbQueueCallback;
+import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
-public class AssetProfileEdgeProcessor extends BaseEdgeProcessor {
+public class AssetProfileEdgeProcessor extends BaseAssetProfileProcessor {
+
+ public ListenableFuture processAssetProfileMsgFromEdge(TenantId tenantId, Edge edge, AssetProfileUpdateMsg assetProfileUpdateMsg) {
+ log.trace("[{}] executing processAssetProfileMsgFromEdge [{}] from edge [{}]", tenantId, assetProfileUpdateMsg, edge.getName());
+ AssetProfileId assetProfileId = new AssetProfileId(new UUID(assetProfileUpdateMsg.getIdMSB(), assetProfileUpdateMsg.getIdLSB()));
+ try {
+ edgeSynchronizationManager.getSync().set(true);
+
+ switch (assetProfileUpdateMsg.getMsgType()) {
+ case ENTITY_CREATED_RPC_MESSAGE:
+ case ENTITY_UPDATED_RPC_MESSAGE:
+ saveOrUpdateAssetProfile(tenantId, assetProfileId, assetProfileUpdateMsg, edge);
+ return Futures.immediateFuture(null);
+ case ENTITY_DELETED_RPC_MESSAGE:
+ case UNRECOGNIZED:
+ default:
+ return handleUnsupportedMsgType(assetProfileUpdateMsg.getMsgType());
+ }
+ } catch (DataValidationException e) {
+ log.warn("Failed to process AssetProfileUpdateMsg from Edge [{}]", assetProfileUpdateMsg, e);
+ return Futures.immediateFailedFuture(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
+
+ private void saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg, Edge edge) {
+ boolean created = super.saveOrUpdateAssetProfile(tenantId, assetProfileId, assetProfileUpdateMsg);
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), assetProfileId);
+ pushAssetProfileCreatedEventToRuleEngine(tenantId, edge, assetProfileId);
+ }
+ }
+
+ private void pushAssetProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetProfileId assetProfileId) {
+ try {
+ AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId);
+ ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(assetProfile);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, assetProfileId, getTbMsgMetaData(edge),
+ TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
+ tbClusterService.pushMsgToRuleEngine(tenantId, assetProfileId, tbMsg, new TbQueueCallback() {
+ @Override
+ public void onSuccess(TbQueueMsgMetadata metadata) {
+ log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", assetProfile);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", assetProfile, t);
+ }
+ });
+ } catch (JsonProcessingException | IllegalArgumentException e) {
+ log.warn("[{}] Failed to push asset profile action to rule engine: {}", assetProfileId, DataConstants.ENTITY_CREATED, e);
+ }
+ }
public DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent) {
AssetProfileId assetProfileId = new AssetProfileId(edgeEvent.getEntityId());
@@ -63,9 +129,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/asset/BaseAssetProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java
new file mode 100644
index 0000000000..5d728cb4e8
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.asset;
+
+import com.datastax.oss.driver.api.core.uuid.Uuids;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.util.Pair;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.id.AssetProfileId;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
+
+@Slf4j
+public abstract class BaseAssetProcessor extends BaseEdgeProcessor {
+
+ protected Pair saveOrUpdateAsset(TenantId tenantId, AssetId assetId, AssetUpdateMsg assetUpdateMsg, CustomerId customerId) {
+ boolean created = false;
+ boolean assetNameUpdated = false;
+ assetCreationLock.lock();
+ try {
+ Asset asset = assetService.findAssetById(tenantId, assetId);
+ String assetName = assetUpdateMsg.getName();
+ if (asset == null) {
+ created = true;
+ asset = new Asset();
+ asset.setTenantId(tenantId);
+ asset.setCreatedTime(Uuids.unixTimestamp(assetId.getId()));
+ }
+ Asset assetByName = assetService.findAssetByTenantIdAndName(tenantId, assetName);
+ if (assetByName != null && !assetByName.getId().equals(assetId)) {
+ assetName = assetName + "_" + StringUtils.randomAlphanumeric(15);
+ log.warn("Asset with name {} already exists. Renaming asset name to {}",
+ assetUpdateMsg.getName(), assetName);
+ assetNameUpdated = true;
+ }
+ asset.setName(assetName);
+ asset.setType(assetUpdateMsg.getType());
+ asset.setLabel(assetUpdateMsg.hasLabel() ? assetUpdateMsg.getLabel() : null);
+ asset.setAdditionalInfo(assetUpdateMsg.hasAdditionalInfo()
+ ? JacksonUtil.toJsonNode(assetUpdateMsg.getAdditionalInfo()) : null);
+
+ UUID assetProfileUUID = safeGetUUID(assetUpdateMsg.getAssetProfileIdMSB(), assetUpdateMsg.getAssetProfileIdLSB());
+ asset.setAssetProfileId(assetProfileUUID != null ? new AssetProfileId(assetProfileUUID) : null);
+
+ asset.setCustomerId(customerId);
+
+ assetValidator.validate(asset, Asset::getTenantId);
+ if (created) {
+ asset.setId(assetId);
+ }
+ assetService.saveAsset(asset, false);
+ } finally {
+ assetCreationLock.unlock();
+ }
+ return Pair.of(created, assetNameUpdated);
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java
new file mode 100644
index 0000000000..4fe778402f
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.asset;
+
+import com.datastax.oss.driver.api.core.uuid.Uuids;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.asset.AssetProfile;
+import org.thingsboard.server.common.data.id.AssetProfileId;
+import org.thingsboard.server.common.data.id.DashboardId;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+@Slf4j
+public class BaseAssetProfileProcessor extends BaseEdgeProcessor {
+
+ protected boolean saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) {
+ boolean created = false;
+ assetCreationLock.lock();
+ try {
+ AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId);
+ String assetProfileName = assetProfileUpdateMsg.getName();
+ if (assetProfile == null) {
+ created = true;
+ assetProfile = new AssetProfile();
+ assetProfile.setTenantId(tenantId);
+ assetProfile.setCreatedTime(Uuids.unixTimestamp(assetProfileId.getId()));
+ }
+ assetProfile.setName(assetProfileName);
+ assetProfile.setDefault(assetProfileUpdateMsg.getDefault());
+ assetProfile.setDefaultQueueName(assetProfileUpdateMsg.hasDefaultQueueName() ? assetProfileUpdateMsg.getDefaultQueueName() : null);
+ assetProfile.setDescription(assetProfileUpdateMsg.hasDescription() ? assetProfileUpdateMsg.getDescription() : null);
+ assetProfile.setImage(assetProfileUpdateMsg.hasImage()
+ ? new String(assetProfileUpdateMsg.getImage().toByteArray(), StandardCharsets.UTF_8) : null);
+
+ UUID defaultRuleChainUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultRuleChainIdMSB(), assetProfileUpdateMsg.getDefaultRuleChainIdLSB());
+ assetProfile.setDefaultRuleChainId(defaultRuleChainUUID != null ? new RuleChainId(defaultRuleChainUUID) : null);
+
+ UUID defaultDashboardUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultDashboardIdMSB(), assetProfileUpdateMsg.getDefaultDashboardIdLSB());
+ assetProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null);
+
+ assetProfileValidator.validate(assetProfile, AssetProfile::getTenantId);
+ if (created) {
+ assetProfile.setId(assetProfileId);
+ }
+ assetProfileService.saveAssetProfile(assetProfile, false);
+ } finally {
+ assetCreationLock.unlock();
+ }
+ return created;
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java
new file mode 100644
index 0000000000..b055c03cf7
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.dashboard;
+
+import com.datastax.oss.driver.api.core.uuid.Uuids;
+import com.fasterxml.jackson.core.type.TypeReference;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.Dashboard;
+import org.thingsboard.server.common.data.ShortCustomerInfo;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.DashboardId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.Set;
+
+@Slf4j
+public abstract class BaseDashboardProcessor extends BaseEdgeProcessor {
+
+ protected boolean saveOrUpdateDashboard(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg, CustomerId customerId) {
+ boolean created = false;
+ Dashboard dashboard = dashboardService.findDashboardById(tenantId, dashboardId);
+ if (dashboard == null) {
+ created = true;
+ dashboard = new Dashboard();
+ dashboard.setTenantId(tenantId);
+ dashboard.setCreatedTime(Uuids.unixTimestamp(dashboardId.getId()));
+ }
+ dashboard.setTitle(dashboardUpdateMsg.getTitle());
+ dashboard.setConfiguration(JacksonUtil.toJsonNode(dashboardUpdateMsg.getConfiguration()));
+ Set assignedCustomers = null;
+ if (dashboardUpdateMsg.hasAssignedCustomers()) {
+ assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() {
+ });
+ dashboard.setAssignedCustomers(assignedCustomers);
+ }
+
+ dashboardValidator.validate(dashboard, Dashboard::getTenantId);
+ if (created) {
+ dashboard.setId(dashboardId);
+ }
+ Dashboard savedDashboard = dashboardService.saveDashboard(dashboard, false);
+ if (assignedCustomers != null && !assignedCustomers.isEmpty()) {
+ for (ShortCustomerInfo assignedCustomer : assignedCustomers) {
+ if (assignedCustomer.getCustomerId().equals(customerId)) {
+ dashboardService.assignDashboardToCustomer(tenantId, dashboardId, assignedCustomer.getCustomerId());
+ }
+ }
+ } else {
+ unassignCustomersFromDashboard(tenantId, savedDashboard);
+ }
+ return created;
+ }
+
+ private void unassignCustomersFromDashboard(TenantId tenantId, Dashboard dashboard) {
+ if (dashboard.getAssignedCustomers() != null && !dashboard.getAssignedCustomers().isEmpty()) {
+ for (ShortCustomerInfo assignedCustomer : dashboard.getAssignedCustomers()) {
+ dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), assignedCustomer.getCustomerId());
+ }
+ }
+ }
+}
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..59f12ec64b 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,25 +15,103 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.dashboard;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Dashboard;
+import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
+import org.thingsboard.server.queue.TbQueueCallback;
+import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
-public class DashboardEdgeProcessor extends BaseEdgeProcessor {
+public class DashboardEdgeProcessor extends BaseDashboardProcessor {
+
+ public ListenableFuture processDashboardMsgFromEdge(TenantId tenantId, Edge edge, DashboardUpdateMsg dashboardUpdateMsg) {
+ log.trace("[{}] executing processDashboardMsgFromEdge [{}] from edge [{}]", tenantId, dashboardUpdateMsg, edge.getName());
+ DashboardId dashboardId = new DashboardId(new UUID(dashboardUpdateMsg.getIdMSB(), dashboardUpdateMsg.getIdLSB()));
+ try {
+ edgeSynchronizationManager.getSync().set(true);
+
+ switch (dashboardUpdateMsg.getMsgType()) {
+ case ENTITY_CREATED_RPC_MESSAGE:
+ case ENTITY_UPDATED_RPC_MESSAGE:
+ saveOrUpdateDashboard(tenantId, dashboardId, dashboardUpdateMsg, edge);
+ return Futures.immediateFuture(null);
+ case ENTITY_DELETED_RPC_MESSAGE:
+ Dashboard dashboardToDelete = dashboardService.findDashboardById(tenantId, dashboardId);
+ if (dashboardToDelete != null) {
+ dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edge.getId());
+ }
+ return Futures.immediateFuture(null);
+ case UNRECOGNIZED:
+ default:
+ return handleUnsupportedMsgType(dashboardUpdateMsg.getMsgType());
+ }
+ } catch (DataValidationException e) {
+ if (e.getMessage().contains("limit reached")) {
+ log.warn("[{}] Number of allowed dashboard violated {}", tenantId, dashboardUpdateMsg, e);
+ return Futures.immediateFuture(null);
+ } else {
+ return Futures.immediateFailedFuture(e);
+ }
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
+
+ private void saveOrUpdateDashboard(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg, Edge edge) {
+ CustomerId customerId = safeGetCustomerId(dashboardUpdateMsg.getCustomerIdMSB(), dashboardUpdateMsg.getCustomerIdLSB());
+ boolean created = super.saveOrUpdateDashboard(tenantId, dashboardId, dashboardUpdateMsg, customerId);
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), dashboardId);
+ pushDashboardCreatedEventToRuleEngine(tenantId, edge, dashboardId);
+ dashboardService.assignDashboardToEdge(tenantId, dashboardId, edge.getId());
+ }
+ }
+
+ private void pushDashboardCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DashboardId dashboardId) {
+ try {
+ Dashboard dashboard = dashboardService.findDashboardById(tenantId, dashboardId);
+ ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(dashboard);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, dashboardId, null,
+ getActionTbMsgMetaData(edge, null), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
+ tbClusterService.pushMsgToRuleEngine(tenantId, dashboardId, tbMsg, new TbQueueCallback() {
+ @Override
+ public void onSuccess(TbQueueMsgMetadata metadata) {
+ log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", dashboard);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", dashboard, t);
+ }
+ });
+ } catch (JsonProcessingException | IllegalArgumentException e) {
+ log.warn("[{}] Failed to push dashboard action to rule engine: {}", dashboardId, DataConstants.ENTITY_CREATED, e);
+ }
+ }
public DownlinkMsg convertDashboardEventToDownlink(EdgeEvent edgeEvent) {
DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId());
@@ -67,8 +145,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..580f752ac1 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
@@ -57,13 +57,13 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
device = new Device();
device.setTenantId(tenantId);
device.setCreatedTime(Uuids.unixTimestamp(deviceId.getId()));
- Device deviceByName = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
- if (deviceByName != null) {
- deviceName = deviceName + "_" + StringUtils.randomAlphabetic(15);
- log.warn("Device with name {} already exists. Renaming device name to {}",
- deviceUpdateMsg.getName(), deviceName);
- deviceNameUpdated = true;
- }
+ }
+ Device deviceByName = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
+ if (deviceByName != null && !deviceByName.getId().equals(deviceId)) {
+ deviceName = deviceName + "_" + StringUtils.randomAlphabetic(15);
+ log.warn("Device with name {} already exists. Renaming device name to {}",
+ deviceUpdateMsg.getName(), deviceName);
+ deviceNameUpdated = true;
}
device.setName(deviceName);
device.setType(deviceUpdateMsg.getType());
@@ -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/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java
new file mode 100644
index 0000000000..662a497528
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.device;
+
+import com.datastax.oss.driver.api.core.uuid.Uuids;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.thingsboard.server.common.data.DeviceProfile;
+import org.thingsboard.server.common.data.DeviceProfileProvisionType;
+import org.thingsboard.server.common.data.DeviceProfileType;
+import org.thingsboard.server.common.data.DeviceTransportType;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
+import org.thingsboard.server.common.data.id.DashboardId;
+import org.thingsboard.server.common.data.id.DeviceProfileId;
+import org.thingsboard.server.common.data.id.OtaPackageId;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
+import org.thingsboard.server.queue.util.DataDecodingEncodingService;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+import java.util.UUID;
+
+@Slf4j
+public class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
+
+ @Autowired
+ private DataDecodingEncodingService dataDecodingEncodingService;
+
+ protected boolean saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
+ boolean created = false;
+ deviceCreationLock.lock();
+ try {
+ DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
+ if (deviceProfile == null) {
+ created = true;
+ deviceProfile = new DeviceProfile();
+ deviceProfile.setTenantId(tenantId);
+ deviceProfile.setCreatedTime(Uuids.unixTimestamp(deviceProfileId.getId()));
+ }
+ deviceProfile.setName(deviceProfileUpdateMsg.getName());
+ deviceProfile.setDescription(deviceProfileUpdateMsg.hasDescription() ? deviceProfileUpdateMsg.getDescription() : null);
+ deviceProfile.setDefault(deviceProfileUpdateMsg.getDefault());
+ deviceProfile.setType(DeviceProfileType.valueOf(deviceProfileUpdateMsg.getType()));
+ deviceProfile.setTransportType(deviceProfileUpdateMsg.hasTransportType()
+ ? DeviceTransportType.valueOf(deviceProfileUpdateMsg.getTransportType()) : DeviceTransportType.DEFAULT);
+ deviceProfile.setImage(deviceProfileUpdateMsg.hasImage()
+ ? new String(deviceProfileUpdateMsg.getImage().toByteArray(), StandardCharsets.UTF_8) : null);
+ deviceProfile.setProvisionType(deviceProfileUpdateMsg.hasProvisionType()
+ ? DeviceProfileProvisionType.valueOf(deviceProfileUpdateMsg.getProvisionType()) : DeviceProfileProvisionType.DISABLED);
+ deviceProfile.setProvisionDeviceKey(deviceProfileUpdateMsg.hasProvisionDeviceKey()
+ ? deviceProfileUpdateMsg.getProvisionDeviceKey() : null);
+ deviceProfile.setDefaultQueueName(deviceProfileUpdateMsg.getDefaultQueueName());
+
+ Optional profileDataOpt =
+ dataDecodingEncodingService.decode(deviceProfileUpdateMsg.getProfileDataBytes().toByteArray());
+ deviceProfile.setProfileData(profileDataOpt.orElse(null));
+
+ UUID defaultRuleChainUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultRuleChainIdMSB(), deviceProfileUpdateMsg.getDefaultRuleChainIdLSB());
+ deviceProfile.setDefaultRuleChainId(defaultRuleChainUUID != null ? new RuleChainId(defaultRuleChainUUID) : null);
+
+ UUID defaultDashboardUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultDashboardIdMSB(), deviceProfileUpdateMsg.getDefaultDashboardIdLSB());
+ deviceProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null);
+
+ String defaultQueueName = StringUtils.isNotBlank(deviceProfileUpdateMsg.getDefaultQueueName())
+ ? deviceProfileUpdateMsg.getDefaultQueueName() : null;
+ deviceProfile.setDefaultQueueName(defaultQueueName);
+
+ UUID firmwareUUID = safeGetUUID(deviceProfileUpdateMsg.getFirmwareIdMSB(), deviceProfileUpdateMsg.getFirmwareIdLSB());
+ deviceProfile.setFirmwareId(firmwareUUID != null ? new OtaPackageId(firmwareUUID) : null);
+
+ UUID softwareUUID = safeGetUUID(deviceProfileUpdateMsg.getSoftwareIdMSB(), deviceProfileUpdateMsg.getSoftwareIdLSB());
+ deviceProfile.setSoftwareId(softwareUUID != null ? new OtaPackageId(softwareUUID) : null);
+
+
+ deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId);
+ if (created) {
+ deviceProfile.setId(deviceProfileId);
+ }
+ deviceProfileService.saveDeviceProfile(deviceProfile, false);
+ } finally {
+ deviceCreationLock.unlock();
+ }
+ return created;
+ }
+}
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..dfa5705840 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
@@ -35,18 +35,14 @@ 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.TenantId;
-import org.thingsboard.server.common.data.relation.EntityRelation;
-import org.thingsboard.server.common.data.relation.RelationTypeGroup;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.data.security.DeviceCredentials;
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 +50,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 +66,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 +90,8 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
} else {
return Futures.immediateFailedFuture(e);
}
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
}
@@ -111,20 +110,11 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
}
}
- private void createRelationFromEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId) {
- EntityRelation relation = new EntityRelation();
- relation.setFrom(edgeId);
- relation.setTo(entityId);
- relation.setTypeGroup(RelationTypeGroup.COMMON);
- relation.setType(EntityRelation.EDGE_TYPE);
- relationService.saveRelation(tenantId, relation);
- }
-
private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceId deviceId) {
try {
Device device = deviceService.findDeviceById(tenantId, deviceId);
ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device);
- TbMsg tbMsg = TbMsg.newMsg(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
@@ -134,27 +124,12 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
@Override
public void onFailure(Throwable t) {
- log.debug("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", device, t);
+ log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", device, t);
}
});
} catch (JsonProcessingException | IllegalArgumentException e) {
- log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, DataConstants.ENTITY_CREATED, e);
- }
- }
-
- private TbMsgMetaData getActionTbMsgMetaData(Edge edge, CustomerId customerId) {
- TbMsgMetaData metaData = getTbMsgMetaData(edge);
- if (customerId != null && !customerId.isNullUid()) {
- metaData.putValue("customerId", customerId.toString());
+ log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, TbMsgType.ENTITY_CREATED.name(), e);
}
- return metaData;
- }
-
- private TbMsgMetaData getTbMsgMetaData(Edge edge) {
- TbMsgMetaData metaData = new TbMsgMetaData();
- metaData.putValue("edgeId", edge.getId().toString());
- metaData.putValue("edgeName", edge.getName());
- return metaData;
}
public ListenableFuture processDeviceRpcCallFromEdge(TenantId tenantId, Edge edge, DeviceRpcCallMsg deviceRpcCallMsg) {
@@ -216,7 +191,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 +283,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..edaffd6f74 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,25 +15,92 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.device;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.edge.Edge;
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.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
+import org.thingsboard.server.queue.TbQueueCallback;
+import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
-public class DeviceProfileEdgeProcessor extends BaseEdgeProcessor {
+public class DeviceProfileEdgeProcessor extends BaseDeviceProfileProcessor {
+
+
+ public ListenableFuture processDeviceProfileMsgFromEdge(TenantId tenantId, Edge edge, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
+ log.trace("[{}] executing processDeviceProfileMsgFromEdge [{}] from edge [{}]", tenantId, deviceProfileUpdateMsg, edge.getName());
+ DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileUpdateMsg.getIdMSB(), deviceProfileUpdateMsg.getIdLSB()));
+ try {
+ edgeSynchronizationManager.getSync().set(true);
+
+ switch (deviceProfileUpdateMsg.getMsgType()) {
+ case ENTITY_CREATED_RPC_MESSAGE:
+ case ENTITY_UPDATED_RPC_MESSAGE:
+ saveOrUpdateDeviceProfile(tenantId, deviceProfileId, deviceProfileUpdateMsg, edge);
+ return Futures.immediateFuture(null);
+ case ENTITY_DELETED_RPC_MESSAGE:
+ case UNRECOGNIZED:
+ default:
+ return handleUnsupportedMsgType(deviceProfileUpdateMsg.getMsgType());
+ }
+ } catch (DataValidationException e) {
+ log.warn("Failed to process DeviceProfileUpdateMsg from Edge [{}]", deviceProfileUpdateMsg, e);
+ return Futures.immediateFailedFuture(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
+
+ private void saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg, Edge edge) {
+ boolean created = super.saveOrUpdateDeviceProfile(tenantId, deviceProfileId, deviceProfileUpdateMsg);
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), deviceProfileId);
+ pushDeviceProfileCreatedEventToRuleEngine(tenantId, edge, deviceProfileId);
+ }
+ }
+
+ private void pushDeviceProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceProfileId deviceProfileId) {
+ try {
+ DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
+ ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(deviceProfile);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceProfileId, getTbMsgMetaData(edge),
+ TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
+ tbClusterService.pushMsgToRuleEngine(tenantId, deviceProfileId, tbMsg, new TbQueueCallback() {
+ @Override
+ public void onSuccess(TbQueueMsgMetadata metadata) {
+ log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", deviceProfile);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", deviceProfile, t);
+ }
+ });
+ } catch (JsonProcessingException | IllegalArgumentException e) {
+ log.warn("[{}] Failed to push device profile action to rule engine: {}", deviceProfileId, DataConstants.ENTITY_CREATED, e);
+ }
+ }
public DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent) {
DeviceProfileId deviceProfileId = new DeviceProfileId(edgeEvent.getEntityId());
@@ -63,8 +130,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/BaseEntityViewProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java
new file mode 100644
index 0000000000..509b2e5196
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.entityview;
+
+import com.datastax.oss.driver.api.core.uuid.Uuids;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.util.Pair;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.EntityView;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.DeviceId;
+import org.thingsboard.server.common.data.id.EntityViewId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.EdgeEntityType;
+import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
+
+@Slf4j
+public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor {
+
+ protected Pair saveOrUpdateEntityView(TenantId tenantId, EntityViewId entityViewId, EntityViewUpdateMsg entityViewUpdateMsg, CustomerId customerId) {
+ boolean created = false;
+ boolean entityViewNameUpdated = false;
+ EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId);
+ String entityViewName = entityViewUpdateMsg.getName();
+ if (entityView == null) {
+ created = true;
+ entityView = new EntityView();
+ entityView.setTenantId(tenantId);
+ entityView.setCreatedTime(Uuids.unixTimestamp(entityViewId.getId()));
+ }
+ EntityView entityViewByName = entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName);
+ if (entityViewByName != null && !entityViewByName.getId().equals(entityViewId)) {
+ entityViewName = entityViewName + "_" + StringUtils.randomAlphanumeric(15);
+ log.warn("Entity view with name {} already exists. Renaming entity view name to {}",
+ entityViewUpdateMsg.getName(), entityViewName);
+ entityViewNameUpdated = true;
+ }
+ entityView.setName(entityViewName);
+ entityView.setType(entityViewUpdateMsg.getType());
+ entityView.setCustomerId(customerId);
+ entityView.setAdditionalInfo(entityViewUpdateMsg.hasAdditionalInfo() ?
+ JacksonUtil.toJsonNode(entityViewUpdateMsg.getAdditionalInfo()) : null);
+
+ UUID entityIdUUID = safeGetUUID(entityViewUpdateMsg.getEntityIdMSB(), entityViewUpdateMsg.getEntityIdLSB());
+ if (EdgeEntityType.DEVICE.equals(entityViewUpdateMsg.getEntityType())) {
+ entityView.setEntityId(entityIdUUID != null ? new DeviceId(entityIdUUID) : null);
+ } else if (EdgeEntityType.ASSET.equals(entityViewUpdateMsg.getEntityType())) {
+ entityView.setEntityId(entityIdUUID != null ? new AssetId(entityIdUUID) : null);
+ }
+
+ entityViewValidator.validate(entityView, EntityView::getTenantId);
+ if (created) {
+ entityView.setId(entityViewId);
+ }
+ entityViewService.saveEntityView(entityView, false);
+ return Pair.of(created, entityViewNameUpdated);
+ }
+}
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..e78b6b4ff5 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,25 +15,111 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.entityview;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityView;
+import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
+import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
+import org.thingsboard.server.queue.TbQueueCallback;
+import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
-public class EntityViewEdgeProcessor extends BaseEdgeProcessor {
+public class EntityViewEdgeProcessor extends BaseEntityViewProcessor {
+
+ public ListenableFuture processEntityViewMsgFromEdge(TenantId tenantId, Edge edge, EntityViewUpdateMsg entityViewUpdateMsg) {
+ log.trace("[{}] executing processEntityViewMsgFromEdge [{}] from edge [{}]", tenantId, entityViewUpdateMsg, edge.getName());
+ EntityViewId entityViewId = new EntityViewId(new UUID(entityViewUpdateMsg.getIdMSB(), entityViewUpdateMsg.getIdLSB()));
+ try {
+ edgeSynchronizationManager.getSync().set(true);
+
+ switch (entityViewUpdateMsg.getMsgType()) {
+ case ENTITY_CREATED_RPC_MESSAGE:
+ case ENTITY_UPDATED_RPC_MESSAGE:
+ saveOrUpdateEntityView(tenantId, entityViewId, entityViewUpdateMsg, edge);
+ return Futures.immediateFuture(null);
+ case ENTITY_DELETED_RPC_MESSAGE:
+ EntityView entityViewToDelete = entityViewService.findEntityViewById(tenantId, entityViewId);
+ if (entityViewToDelete != null) {
+ entityViewService.unassignEntityViewFromEdge(tenantId, entityViewId, edge.getId());
+ }
+ return Futures.immediateFuture(null);
+ case UNRECOGNIZED:
+ default:
+ return handleUnsupportedMsgType(entityViewUpdateMsg.getMsgType());
+ }
+ } catch (DataValidationException e) {
+ if (e.getMessage().contains("limit reached")) {
+ log.warn("[{}] Number of allowed entity views violated {}", tenantId, entityViewUpdateMsg, e);
+ return Futures.immediateFuture(null);
+ } else {
+ return Futures.immediateFailedFuture(e);
+ }
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
+
+ private void saveOrUpdateEntityView(TenantId tenantId, EntityViewId entityViewId, EntityViewUpdateMsg entityViewUpdateMsg, Edge edge) {
+ CustomerId customerId = safeGetCustomerId(entityViewUpdateMsg.getCustomerIdMSB(), entityViewUpdateMsg.getCustomerIdLSB());
+ Pair resultPair = super.saveOrUpdateEntityView(tenantId, entityViewId, entityViewUpdateMsg, customerId);
+ Boolean created = resultPair.getFirst();
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), entityViewId);
+ pushAssetCreatedEventToRuleEngine(tenantId, edge, entityViewId);
+ entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edge.getId());
+ }
+ Boolean assetNameUpdated = resultPair.getSecond();
+ if (assetNameUpdated) {
+ saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW, EdgeEventActionType.UPDATED, entityViewId, null);
+ }
+ }
+
+ private void pushAssetCreatedEventToRuleEngine(TenantId tenantId, Edge edge, EntityViewId entityViewId) {
+ try {
+ EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId);
+ ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(entityView);
+ TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, entityViewId, entityView.getCustomerId(),
+ getActionTbMsgMetaData(edge, entityView.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
+ tbClusterService.pushMsgToRuleEngine(tenantId, entityViewId, tbMsg, new TbQueueCallback() {
+ @Override
+ public void onSuccess(TbQueueMsgMetadata metadata) {
+ log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", entityView);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", entityView, t);
+ }
+ });
+ } catch (JsonProcessingException | IllegalArgumentException e) {
+ log.warn("[{}] Failed to push entity view action to rule engine: {}", entityViewId, DataConstants.ENTITY_CREATED, e);
+ }
+ }
public DownlinkMsg convertEntityViewEventToDownlink(EdgeEvent edgeEvent) {
EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId());
@@ -67,8 +153,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/tenant/TenantEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantEdgeProcessor.java
new file mode 100644
index 0000000000..9bd87660d2
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantEdgeProcessor.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.tenant;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.TenantProfile;
+import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
+import org.thingsboard.server.gen.edge.v1.TenantProfileUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.TenantUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+@Component
+@Slf4j
+@TbCoreComponent
+public class TenantEdgeProcessor extends BaseEdgeProcessor {
+
+ public DownlinkMsg convertTenantEventToDownlink(EdgeEvent edgeEvent) {
+ TenantId tenantId = new TenantId(edgeEvent.getEntityId());
+ DownlinkMsg downlinkMsg = null;
+ if (EdgeEventActionType.UPDATED.equals(edgeEvent.getAction())) {
+ Tenant tenant = tenantService.findTenantById(tenantId);
+ if (tenant != null) {
+ UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
+ TenantUpdateMsg tenantUpdateMsg = tenantMsgConstructor.constructTenantUpdateMsg(msgType, tenant);
+ TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(tenantId, tenant.getTenantProfileId());
+ TenantProfileUpdateMsg tenantProfileUpdateMsg = tenantProfileMsgConstructor.constructTenantProfileUpdateMsg(msgType, tenantProfile);
+ downlinkMsg = DownlinkMsg.newBuilder()
+ .setDownlinkMsgId(EdgeUtils.nextPositiveInt())
+ .addTenantUpdateMsg(tenantUpdateMsg)
+ .addTenantProfileUpdateMsg(tenantProfileUpdateMsg)
+ .build();
+ }
+ }
+ return downlinkMsg;
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantProfileEdgeProcessor.java
new file mode 100644
index 0000000000..c9071571c4
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantProfileEdgeProcessor.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.tenant;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.TenantProfile;
+import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.id.TenantProfileId;
+import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
+import org.thingsboard.server.gen.edge.v1.TenantProfileUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+@Component
+@Slf4j
+@TbCoreComponent
+public class TenantProfileEdgeProcessor extends BaseEdgeProcessor {
+
+ public DownlinkMsg convertTenantProfileEventToDownlink(EdgeEvent edgeEvent) {
+ TenantProfileId tenantProfileId = new TenantProfileId(edgeEvent.getEntityId());
+ DownlinkMsg downlinkMsg = null;
+ if (EdgeEventActionType.UPDATED.equals(edgeEvent.getAction())) {
+ TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(edgeEvent.getTenantId(), tenantProfileId);
+ if (tenantProfile != null) {
+ UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
+ TenantProfileUpdateMsg tenantProfileUpdateMsg =
+ tenantProfileMsgConstructor.constructTenantProfileUpdateMsg(msgType, tenantProfile);
+ downlinkMsg = DownlinkMsg.newBuilder()
+ .setDownlinkMsgId(EdgeUtils.nextPositiveInt())
+ .addTenantProfileUpdateMsg(tenantProfileUpdateMsg)
+ .build();
+ }
+ }
+ return downlinkMsg;
+ }
+}
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/edge/rpc/sync/DefaultEdgeRequestsService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
index 700e0f3861..86a97f33db 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
@@ -167,6 +167,8 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
attributes.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
attributes.put(attr.getKey(), attr.getLongValue().get());
+ } else if (attr.getDataType() == DataType.JSON && attr.getJsonValue().isPresent()) {
+ attributes.set(attr.getKey(), JacksonUtil.toJsonNode(attr.getJsonValue().get()));
} else {
attributes.put(attr.getKey(), attr.getValueAsString());
}
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 caf65d39ec..2dc246d9a7 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
@@ -29,16 +29,20 @@ import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
+import org.thingsboard.server.common.data.alarm.AlarmQueryV2;
import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
-import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
@Service
@AllArgsConstructor
@@ -62,10 +66,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);
@@ -80,6 +80,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);
@@ -98,6 +102,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())
@@ -112,11 +117,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
@@ -130,6 +136,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())
@@ -144,11 +151,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
@@ -175,7 +183,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);
}
@@ -203,19 +212,53 @@ 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);
}
return alarmInfo;
}
+ @Override
+ public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) {
+ AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build();
+ try {
+ List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData();
+ for (AlarmInfo alarm : alarms) {
+ AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs));
+ if (!result.isSuccessful()) {
+ continue;
+ }
+ if (result.isModified()) {
+ AlarmComment alarmComment = AlarmComment.builder()
+ .alarmId(alarm.getId())
+ .type(AlarmCommentType.SYSTEM)
+ .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted",
+ (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))
+ .put("userId", user.getId().toString())
+ .put("subtype", "ASSIGN"))
+ .build();
+ try {
+ alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
+ } catch (ThingsboardException e) {
+ log.error("Failed to save alarm comment", e);
+ }
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(),
+ alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, user);
+ }
+ }
+
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@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/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
index a2ae9c8cc7..24af185539 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
@@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
public interface TbAlarmService {
@@ -37,5 +38,7 @@ public interface TbAlarmService {
AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException;
+ void unassignUserAlarms(TenantId tenantId, User user, long unassignTs);
+
Boolean delete(Alarm alarm, User user);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/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..b0ef8f4cde 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
@@ -15,12 +15,11 @@
*/
package org.thingsboard.server.service.entitiy.queue;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
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;
@@ -28,7 +27,6 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfi
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.queue.TbQueueAdmin;
-import org.thingsboard.server.queue.scheduler.SchedulerComponent;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
@@ -36,20 +34,17 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
@TbCoreComponent
-@AllArgsConstructor
+@RequiredArgsConstructor
public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService {
- private static final long DELETE_DELAY = 30;
private final QueueService queueService;
private final TbClusterService tbClusterService;
private final TbQueueAdmin tbQueueAdmin;
- private final SchedulerComponent scheduler;
@Override
public Queue saveQueue(Queue queue) {
@@ -71,8 +66,6 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
onQueueUpdated(savedQueue, oldQueue);
}
- notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), savedQueue.getId(), create ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
-
return savedQueue;
}
@@ -93,7 +86,9 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
private void onQueueCreated(Queue queue) {
for (int i = 0; i < queue.getPartitions(); i++) {
tbQueueAdmin.createTopicIfNotExists(
- new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName());
+ new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(),
+ queue.getCustomProperties()
+ );
}
tbClusterService.onQueueChange(queue);
@@ -108,21 +103,15 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName());
for (int i = oldPartitions; i < currentPartitions; i++) {
tbQueueAdmin.createTopicIfNotExists(
- new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName());
+ new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(),
+ queue.getCustomProperties()
+ );
}
tbClusterService.onQueueChange(queue);
} else {
log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName());
tbClusterService.onQueueChange(queue);
-
- scheduler.schedule(() -> {
- for (int i = currentPartitions; i < oldPartitions; i++) {
- String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName();
- log.info("Removed partition [{}]", fullTopicName);
- tbQueueAdmin.deleteTopic(
- fullTopicName);
- }
- }, DELETE_DELAY, TimeUnit.SECONDS);
+ // TODO: move all the messages left in old partitions and delete topics
}
} else if (!oldQueue.equals(queue)) {
tbClusterService.onQueueChange(queue);
@@ -131,22 +120,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
private void onQueueDeleted(Queue queue) {
tbClusterService.onQueueDelete(queue);
-
// queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId);
-
- scheduler.schedule(() -> {
- for (int i = 0; i < queue.getPartitions(); i++) {
- String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName();
- log.info("Deleting queue [{}]", fullTopicName);
- try {
- tbQueueAdmin.deleteTopic(fullTopicName);
- } catch (Exception e) {
- log.error("Failed to delete queue [{}]", fullTopicName);
- }
- }
- }, DELETE_DELAY, TimeUnit.SECONDS);
-
- notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), queue.getId(), EdgeEventActionType.DELETED);
}
@Override
@@ -198,6 +172,10 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
}
}
+ if (log.isDebugEnabled()) {
+ log.debug("[{}] Handling profile queue config update: creating queues {}, updating {}, deleting {}. Affected tenants: {}",
+ newTenantProfile.getUuidId(), toCreate, toUpdate, toRemove, tenantIds);
+ }
tenantIds.forEach(tenantId -> {
toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key))));
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/DefaultTbTenantProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/DefaultTbTenantProfileService.java
index 1219a5b929..15bcc2e040 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/DefaultTbTenantProfileService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/DefaultTbTenantProfileService.java
@@ -44,16 +44,14 @@ public class DefaultTbTenantProfileService extends AbstractTbEntityService imple
@Override
public TenantProfile save(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) throws ThingsboardException {
TenantProfile savedTenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(tenantId, tenantProfile));
- if (oldTenantProfile != null && savedTenantProfile.isIsolatedTbRuleEngine()) {
- List tenantIds = tenantService.findTenantIdsByTenantProfileId(savedTenantProfile.getId());
- tbQueueService.updateQueuesByTenants(tenantIds, savedTenantProfile, oldTenantProfile);
- }
-
tenantProfileCache.put(savedTenantProfile);
tbClusterService.onTenantProfileChange(savedTenantProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(TenantId.SYS_TENANT_ID, savedTenantProfile.getId(),
tenantProfile.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
+ List tenantIds = tenantService.findTenantIdsByTenantProfileId(savedTenantProfile.getId());
+ tbQueueService.updateQueuesByTenants(tenantIds, savedTenantProfile, oldTenantProfile);
+
return savedTenantProfile;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/TbTenantProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/TbTenantProfileService.java
index c45d3314cd..2588f4a82c 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/TbTenantProfileService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/TbTenantProfileService.java
@@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
public interface TbTenantProfileService {
+
TenantProfile save(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) throws ThingsboardException;
void delete(TenantId tenantId, TenantProfile tenantProfile) throws ThingsboardException;
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 c83c48cc8a..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
@@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import org.thingsboard.server.service.entitiy.alarm.TbAlarmService;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import javax.servlet.http.HttpServletRequest;
@@ -43,6 +44,7 @@ import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATT
public class DefaultUserService extends AbstractTbEntityService implements TbUserService {
private final UserService userService;
+ private final TbAlarmService tbAlarmService;
private final MailService mailService;
private final SystemSecurityService systemSecurityService;
@@ -52,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);
@@ -66,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);
@@ -77,15 +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(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/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
index 34515f827d..2e2b3e96be 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
@@ -756,6 +756,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_rule_node_type_configuration_version ON rule_node(type, configuration_version);");
} catch (Exception e) {
}
+ try {
+ conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_unread ON notification(recipient_id) WHERE status <> 'READ';");
+ } catch (Exception e) {
+ }
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3005002;");
}
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 f832b04c21..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;
@@ -202,22 +203,27 @@ public class DefaultDataUpdateService implements DataUpdateService {
} else {
log.info("Skipping audit logs migration");
}
- boolean skipEdgeEventsMigration = getEnv("TB_SKIP_EDGE_EVENTS_MIGRATION", false);
- if (!skipEdgeEventsMigration) {
- log.info("Starting edge events migration. Can be skipped with TB_SKIP_EDGE_EVENTS_MIGRATION env variable set to true");
- edgeEventDao.migrateEdgeEvents();
- } else {
- log.info("Skipping edge events migration");
- }
+ migrateEdgeEvents("Starting edge events migration. ");
break;
case "3.5.1":
log.info("Updating data from version 3.5.1 to 3.5.2 ...");
+ migrateEdgeEvents("Starting edge events migration - adding seq_id column. ");
break;
default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
}
}
+ private void migrateEdgeEvents(String logPrefix) {
+ boolean skipEdgeEventsMigration = getEnv("TB_SKIP_EDGE_EVENTS_MIGRATION", false);
+ if (!skipEdgeEventsMigration) {
+ log.info(logPrefix + "Can be skipped with TB_SKIP_EDGE_EVENTS_MIGRATION env variable set to true");
+ edgeEventDao.migrateEdgeEvents();
+ } else {
+ log.info("Skipping edge events migration");
+ }
+ }
+
@Override
public void upgradeRuleNodes() {
try {
@@ -497,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/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
index cb77cc0948..16d4c44d63 100644
--- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
+++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
@@ -39,6 +39,8 @@ import org.thingsboard.server.common.data.notification.NotificationRequestStatus
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
+import org.thingsboard.server.common.data.notification.targets.MicrosoftTeamsNotificationTargetConfig;
+import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
@@ -210,6 +212,11 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
recipients = List.of(targetConfig.getConversation());
break;
}
+ case MICROSOFT_TEAMS: {
+ MicrosoftTeamsNotificationTargetConfig targetConfig = (MicrosoftTeamsNotificationTargetConfig) target.getConfiguration();
+ recipients = List.of(targetConfig);
+ break;
+ }
default: {
recipients = Collections.emptyList();
}
@@ -237,7 +244,17 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
private void processForRecipient(NotificationDeliveryMethod deliveryMethod, NotificationRecipient recipient, NotificationProcessingContext ctx) throws Exception {
if (ctx.getStats().contains(deliveryMethod, recipient.getId())) {
throw new AlreadySentException();
+ } else {
+ ctx.getStats().reportProcessed(deliveryMethod, recipient.getId());
}
+
+ if (recipient instanceof User) {
+ UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), ((User) recipient).getId(), false);
+ if (!settings.isEnabled(ctx.getNotificationType(), deliveryMethod)) {
+ throw new RuntimeException("User disabled " + deliveryMethod.getName() + " notifications of this type");
+ }
+ }
+
NotificationChannel notificationChannel = channels.get(deliveryMethod);
DeliveryMethodNotificationTemplate processedTemplate = ctx.getProcessedTemplate(deliveryMethod, recipient);
@@ -251,7 +268,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
Notification notification = Notification.builder()
.requestId(request.getId())
.recipientId(recipient.getId())
- .type(ctx.getNotificationTemplate().getNotificationType())
+ .type(ctx.getNotificationType())
.subject(processedTemplate.getSubject())
.text(processedTemplate.getBody())
.additionalConfig(processedTemplate.getAdditionalConfig())
diff --git a/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java b/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java
index 27a9cabe43..e91a3e80fa 100644
--- a/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java
+++ b/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java
@@ -18,19 +18,18 @@ package org.thingsboard.server.service.notification;
import com.google.common.base.Strings;
import lombok.Builder;
import lombok.Getter;
-import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
+import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
-import org.thingsboard.server.common.data.notification.template.HasSubject;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
-import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.util.TemplateUtils;
import java.util.EnumMap;
@@ -38,8 +37,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import static org.apache.commons.lang3.StringUtils.isNotEmpty;
-
@SuppressWarnings("unchecked")
public class NotificationProcessingContext {
@@ -52,6 +49,8 @@ public class NotificationProcessingContext {
private final Set deliveryMethods;
@Getter
private final NotificationTemplate notificationTemplate;
+ @Getter
+ private final NotificationType notificationType;
private final Map templates;
@Getter
@@ -65,6 +64,7 @@ public class NotificationProcessingContext {
this.deliveryMethods = deliveryMethods;
this.settings = settings;
this.notificationTemplate = template;
+ this.notificationType = template.getNotificationType();
this.templates = new EnumMap<>(NotificationDeliveryMethod.class);
this.stats = new NotificationRequestStats();
init();
@@ -86,12 +86,11 @@ public class NotificationProcessingContext {
public T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, NotificationRecipient recipient) {
T template = (T) templates.get(deliveryMethod);
- Map additionalTemplateContext = null;
if (recipient != null) {
- additionalTemplateContext = createTemplateContextForRecipient(recipient);
- }
- if (MapUtils.isNotEmpty(additionalTemplateContext) && template.containsAny(additionalTemplateContext.keySet().toArray(String[]::new))) {
- template = processTemplate(template, additionalTemplateContext);
+ Map additionalTemplateContext = createTemplateContextForRecipient(recipient);
+ if (template.getTemplatableValues().stream().anyMatch(value -> value.containsParams(additionalTemplateContext.keySet()))) {
+ template = processTemplate(template, additionalTemplateContext);
+ }
}
return template;
}
@@ -107,22 +106,13 @@ public class NotificationProcessingContext {
if (templateContext.isEmpty()) return template;
template = (T) template.copy();
- template.setBody(TemplateUtils.processTemplate(template.getBody(), templateContext));
- if (template instanceof HasSubject) {
- String subject = ((HasSubject) template).getSubject();
- ((HasSubject) template).setSubject(TemplateUtils.processTemplate(subject, templateContext));
- }
- if (template instanceof WebDeliveryMethodNotificationTemplate) {
- WebDeliveryMethodNotificationTemplate webNotificationTemplate = (WebDeliveryMethodNotificationTemplate) template;
- String buttonText = webNotificationTemplate.getButtonText();
- if (isNotEmpty(buttonText)) {
- webNotificationTemplate.setButtonText(TemplateUtils.processTemplate(buttonText, templateContext));
- }
- String buttonLink = webNotificationTemplate.getButtonLink();
- if (isNotEmpty(buttonLink)) {
- webNotificationTemplate.setButtonLink(TemplateUtils.processTemplate(buttonLink, templateContext));
+ template.getTemplatableValues().forEach(templatableValue -> {
+ String value = templatableValue.get();
+ if (StringUtils.isNotEmpty(value)) {
+ value = TemplateUtils.processTemplate(value, templateContext);
+ templatableValue.set(value);
}
- }
+ });
return template;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/notification/channels/MicrosoftTeamsNotificationChannel.java b/application/src/main/java/org/thingsboard/server/service/notification/channels/MicrosoftTeamsNotificationChannel.java
new file mode 100644
index 0000000000..8720505267
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/notification/channels/MicrosoftTeamsNotificationChannel.java
@@ -0,0 +1,194 @@
+/**
+ * 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.notification.channels;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Strings;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
+import org.thingsboard.server.common.data.notification.info.NotificationInfo;
+import org.thingsboard.server.common.data.notification.targets.MicrosoftTeamsNotificationTargetConfig;
+import org.thingsboard.server.common.data.notification.template.MicrosoftTeamsDeliveryMethodNotificationTemplate;
+import org.thingsboard.server.common.data.notification.template.MicrosoftTeamsDeliveryMethodNotificationTemplate.Button.LinkType;
+import org.thingsboard.server.service.notification.NotificationProcessingContext;
+import org.thingsboard.server.service.security.system.SystemSecurityService;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.Optional;
+
+@Component
+@RequiredArgsConstructor
+public class MicrosoftTeamsNotificationChannel implements NotificationChannel {
+
+ private final SystemSecurityService systemSecurityService;
+
+ @Setter
+ private RestTemplate restTemplate = new RestTemplateBuilder()
+ .setConnectTimeout(Duration.of(15, ChronoUnit.SECONDS))
+ .setReadTimeout(Duration.of(15, ChronoUnit.SECONDS))
+ .build();
+
+ @Override
+ public void sendNotification(MicrosoftTeamsNotificationTargetConfig targetConfig, MicrosoftTeamsDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) throws Exception {
+ Message message = new Message();
+ message.setThemeColor(Strings.emptyToNull(processedTemplate.getThemeColor()));
+ if (StringUtils.isEmpty(processedTemplate.getSubject())) {
+ message.setText(processedTemplate.getBody());
+ } else {
+ message.setSummary(processedTemplate.getSubject());
+ Message.Section section = new Message.Section();
+ section.setActivityTitle(processedTemplate.getSubject());
+ section.setActivitySubtitle(processedTemplate.getBody());
+ message.setSections(List.of(section));
+ }
+ var button = processedTemplate.getButton();
+ if (button != null && button.isEnabled()) {
+ String uri;
+ if (button.getLinkType() == LinkType.DASHBOARD) {
+ String state = null;
+ if (button.isSetEntityIdInState() || StringUtils.isNotEmpty(button.getDashboardState())) {
+ ObjectNode stateObject = JacksonUtil.newObjectNode();
+ if (button.isSetEntityIdInState()) {
+ stateObject.putObject("params")
+ .set("entityId", Optional.ofNullable(ctx.getRequest().getInfo())
+ .map(NotificationInfo::getStateEntityId)
+ .map(JacksonUtil::valueToTree)
+ .orElse(null));
+ } else {
+ stateObject.putObject("params");
+ }
+ if (StringUtils.isNotEmpty(button.getDashboardState())) {
+ stateObject.put("id", button.getDashboardState());
+ }
+ state = Base64.encodeBase64String(JacksonUtil.OBJECT_MAPPER.writeValueAsBytes(List.of(stateObject)));
+ }
+ String baseUrl = systemSecurityService.getBaseUrl(ctx.getTenantId(), null, null);
+ if (StringUtils.isEmpty(baseUrl)) {
+ throw new IllegalStateException("Failed to determine base url to construct dashboard link");
+ }
+ uri = baseUrl + "/dashboards/" + button.getDashboardId();
+ if (state != null) {
+ uri += "?state=" + state;
+ }
+ } else {
+ uri = button.getLink();
+ }
+ if (StringUtils.isNotBlank(uri) && button.getText() != null) {
+ Message.ActionCard actionCard = new Message.ActionCard();
+ actionCard.setType("OpenUri");
+ actionCard.setName(button.getText());
+ var target = new Message.ActionCard.Target("default", uri);
+ actionCard.setTargets(List.of(target));
+ message.setPotentialAction(List.of(actionCard));
+ }
+ }
+
+ restTemplate.postForEntity(targetConfig.getWebhookUrl(), message, String.class);
+ }
+
+ @Override
+ public void check(TenantId tenantId) throws Exception {
+ }
+
+ @Override
+ public NotificationDeliveryMethod getDeliveryMethod() {
+ return NotificationDeliveryMethod.MICROSOFT_TEAMS;
+ }
+
+ @Data
+ public static class Message {
+ @JsonProperty("@type")
+ private final String type = "MessageCard";
+ @JsonProperty("@context")
+ private final String context = "http://schema.org/extensions";
+ private String themeColor;
+ private String summary;
+ private String text;
+ private List sections;
+ private List potentialAction;
+
+ @Data
+ public static class Section {
+ private String activityTitle;
+ private String activitySubtitle;
+ private String activityImage;
+ private List facts;
+ private boolean markdown;
+
+ @Data
+ public static class Fact {
+ private final String name;
+ private final String value;
+ }
+ }
+
+ @Data
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public static class ActionCard {
+ @JsonProperty("@type")
+ private String type; // ActionCard, OpenUri
+ private String name;
+ private List inputs; // for ActionCard
+ private List actions; // for ActionCard
+ private List targets;
+
+ @Data
+ public static class Input {
+ @JsonProperty("@type")
+ private String type; // TextInput, DateInput, MultichoiceInput
+ private String id;
+ private boolean isMultiple;
+ private String title;
+ private boolean isMultiSelect;
+
+ @Data
+ public static class Choice {
+ private final String display;
+ private final String value;
+ }
+ }
+
+ @Data
+ public static class Action {
+ @JsonProperty("@type")
+ private final String type; // HttpPOST
+ private final String name;
+ private final String target; // url
+ }
+
+ @Data
+ public static class Target {
+ private final String os;
+ private final String uri;
+ }
+ }
+
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
index d69d502aa2..a942dce736 100644
--- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
@@ -108,6 +108,8 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor>> consumers = new ConcurrentHashMap<>();
private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>();
private final ConcurrentMap consumerStats = new ConcurrentHashMap<>();
@@ -128,7 +136,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
TbTenantProfileCache tenantProfileCache,
TbApiUsageStateService apiUsageStateService,
PartitionService partitionService, ApplicationEventPublisher eventPublisher,
- TbServiceInfoProvider serviceInfoProvider, QueueService queueService) {
+ TbServiceInfoProvider serviceInfoProvider, QueueService queueService,
+ TbQueueProducerProvider producerProvider, TbQueueAdmin queueAdmin) {
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty());
this.statisticsService = statisticsService;
this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory;
@@ -138,6 +147,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
this.statsFactory = statsFactory;
this.serviceInfoProvider = serviceInfoProvider;
this.queueService = queueService;
+ this.producerProvider = producerProvider;
+ this.queueAdmin = queueAdmin;
}
@PostConstruct
@@ -145,14 +156,16 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
super.init("tb-rule-engine-consumer", "tb-rule-engine-notifications-consumer");
List queues = queueService.findAllQueues();
for (Queue configuration : queues) {
- initConsumer(configuration);
+ if (partitionService.isManagedByCurrentService(configuration.getTenantId())) {
+ initConsumer(configuration);
+ }
}
}
private void initConsumer(Queue configuration) {
QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, configuration);
consumerConfigurations.putIfAbsent(queueKey, configuration);
- consumerStats.putIfAbsent(queueKey, new TbRuleEngineConsumerStats(configuration.getName(), statsFactory));
+ consumerStats.putIfAbsent(queueKey, new TbRuleEngineConsumerStats(configuration, statsFactory));
if (!configuration.isConsumerPerPartition()) {
consumers.computeIfAbsent(queueKey, queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration));
} else {
@@ -172,7 +185,12 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
if (event.getServiceType().equals(getServiceType())) {
String serviceQueue = event.getQueueKey().getQueueName();
log.info("[{}] Subscribing to partitions: {}", serviceQueue, event.getPartitions());
- if (!consumerConfigurations.get(event.getQueueKey()).isConsumerPerPartition()) {
+ Queue configuration = consumerConfigurations.get(event.getQueueKey());
+ if (configuration == null) {
+ log.warn("Received invalid partition change event for {} that is not managed by this service", event.getQueueKey());
+ return;
+ }
+ if (!configuration.isConsumerPerPartition()) {
consumers.get(event.getQueueKey()).subscribe(event.getPartitions());
} else {
log.info("[{}] Subscribing consumer per partition: {}", serviceQueue, event.getPartitions());
@@ -230,7 +248,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
launchConsumer(consumer, consumerConfigurations.get(queueKey), consumerStats.get(queueKey), "" + queueKey + "-" + tpi.getPartition().orElse(-999999));
consumer.subscribe(Collections.singleton(tpi));
});
-
} finally {
tbTopicWithConsumerPerPartition.getLock().unlock();
}
@@ -259,14 +276,28 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
}
void launchConsumer(TbQueueConsumer> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) {
- consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix));
+ if (isReady) {
+ consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix));
+ } else {
+ scheduleLaunchConsumer(consumer, configuration, stats, threadSuffix);
+ }
+ }
+
+ private void scheduleLaunchConsumer(TbQueueConsumer> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) {
+ repartitionExecutor.schedule(() -> {
+ if (isReady) {
+ consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix));
+ } else {
+ scheduleLaunchConsumer(consumer, configuration, stats, threadSuffix);
+ }
+ }, 10, TimeUnit.SECONDS);
}
void consumerLoop(TbQueueConsumer> consumer, org.thingsboard.server.common.data.queue.Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) {
updateCurrentThreadName(threadSuffix);
- while (!stopped && !consumer.isStopped()) {
+ while (!stopped && !consumer.isStopped() && !consumer.isQueueDeleted()) {
try {
- List> msgs = consumer.poll(pollDuration);
+ List> msgs = consumer.poll(configuration.getPollInterval());
if (msgs.isEmpty()) {
continue;
}
@@ -314,6 +345,10 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
}
}
}
+
+ if (consumer.isQueueDeleted()) {
+ processQueueDeletion(configuration, consumer);
+ }
log.info("TB Rule Engine Consumer stopped.");
}
@@ -349,7 +384,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
callback.onSuccess();
}
} catch (Exception e) {
- callback.onFailure(new RuleEngineException(e.getMessage()));
+ callback.onFailure(new RuleEngineException(e.getMessage(), e));
}
}
@@ -411,32 +446,34 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
private void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) {
log.info("Received queue update msg: [{}]", queueUpdateMsg);
- String queueName = queueUpdateMsg.getQueueName();
TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB()));
- QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB()));
- QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName(), tenantId);
- Queue queue = queueService.findQueueById(tenantId, queueId);
- Queue oldQueue = consumerConfigurations.remove(queueKey);
- if (oldQueue != null) {
- if (oldQueue.isConsumerPerPartition()) {
- TbTopicWithConsumerPerPartition consumerPerPartition = topicsConsumerPerPartition.remove(queueKey);
- ReentrantLock lock = consumerPerPartition.getLock();
- try {
- lock.lock();
- consumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe);
- } finally {
- lock.unlock();
+ if (partitionService.isManagedByCurrentService(tenantId)) {
+ QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB()));
+ String queueName = queueUpdateMsg.getQueueName();
+ QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueName, tenantId);
+ Queue queue = queueService.findQueueById(tenantId, queueId);
+ Queue oldQueue = consumerConfigurations.remove(queueKey);
+ if (oldQueue != null) {
+ if (oldQueue.isConsumerPerPartition()) {
+ TbTopicWithConsumerPerPartition consumerPerPartition = topicsConsumerPerPartition.remove(queueKey);
+ ReentrantLock lock = consumerPerPartition.getLock();
+ try {
+ lock.lock();
+ consumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe);
+ } finally {
+ lock.unlock();
+ }
+ } else {
+ TbQueueConsumer> consumer = consumers.remove(queueKey);
+ consumer.unsubscribe();
}
- } else {
- TbQueueConsumer> consumer = consumers.remove(queueKey);
- consumer.unsubscribe();
}
- }
- initConsumer(queue);
+ initConsumer(queue);
- if (!queue.isConsumerPerPartition()) {
- launchConsumer(consumers.get(queueKey), consumerConfigurations.get(queueKey), consumerStats.get(queueKey), queueName);
+ if (!queue.isConsumerPerPartition()) {
+ launchConsumer(consumers.get(queueKey), consumerConfigurations.get(queueKey), consumerStats.get(queueKey), queueName);
+ }
}
partitionService.updateQueue(queueUpdateMsg);
@@ -448,22 +485,22 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB()));
QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId);
+ partitionService.removeQueue(queueDeleteMsg);
Queue queue = consumerConfigurations.remove(queueKey);
if (queue != null) {
if (queue.isConsumerPerPartition()) {
TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.remove(queueKey);
if (tbTopicWithConsumerPerPartition != null) {
- tbTopicWithConsumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe);
+ tbTopicWithConsumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::onQueueDelete);
tbTopicWithConsumerPerPartition.getConsumers().clear();
}
} else {
TbQueueConsumer> consumer = consumers.remove(queueKey);
if (consumer != null) {
- consumer.unsubscribe();
+ consumer.onQueueDelete();
}
}
}
- partitionService.removeQueue(queueDeleteMsg);
}
private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) {
@@ -482,6 +519,47 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
actorContext.tell(msg);
}
+ private void processQueueDeletion(Queue queue, TbQueueConsumer> consumer) {
+ long finishTs = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(topicDeletionDelayInSec);
+ try {
+ int n = 0;
+ while (System.currentTimeMillis() <= finishTs) {
+ List> msgs = consumer.poll(queue.getPollInterval());
+ if (msgs.isEmpty()) {
+ continue;
+ }
+ for (TbProtoQueueMsg msg : msgs) {
+ try {
+ MsgProtos.TbMsgProto tbMsgProto = MsgProtos.TbMsgProto.parseFrom(msg.getValue().getTbMsg().toByteArray());
+ EntityId originator = EntityIdFactory.getByTypeAndUuid(tbMsgProto.getEntityType(), new UUID(tbMsgProto.getEntityIdMSB(), tbMsgProto.getEntityIdLSB()));
+
+ TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, queue.getName(), TenantId.SYS_TENANT_ID, originator);
+ producerProvider.getRuleEngineMsgProducer().send(tpi, msg, null);
+ n++;
+ } catch (Throwable e) {
+ log.debug("Failed to move message to system {}: {}", consumer.getTopic(), msg, e);
+ }
+ }
+ consumer.commit();
+ }
+ if (n > 0) {
+ log.info("Moved {} messages from {} to system {}", n, consumer.getFullTopicNames(), consumer.getTopic());
+ }
+
+ consumer.unsubscribe();
+ for (String topic : consumer.getFullTopicNames()) {
+ try {
+ queueAdmin.deleteTopic(topic);
+ log.info("Deleted topic {}", topic);
+ } catch (Exception e) {
+ log.error("Failed to delete topic {} after unsubscribing", topic, e);
+ }
+ }
+ } catch (Exception e) {
+ log.error("Failed to process deletion of {} ({})", consumer.getTopic(), queue.getTenantId(), e);
+ }
+ }
+
@Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}")
public void printStats() {
if (statsEnabled) {
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
index 400586235e..ea90364ef7 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
@@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.TenantNotFoundException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
-import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.discovery.TenantRoutingInfo;
import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
@@ -31,12 +30,9 @@ import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core' || '${service.type:null}'=='tb-rule-engine'")
public class DefaultTenantRoutingInfoService implements TenantRoutingInfoService {
- private final TenantService tenantService;
-
private final TbTenantProfileCache tenantProfileCache;
- public DefaultTenantRoutingInfoService(TenantService tenantService, TbTenantProfileCache tenantProfileCache) {
- this.tenantService = tenantService;
+ public DefaultTenantRoutingInfoService(TbTenantProfileCache tenantProfileCache) {
this.tenantProfileCache = tenantProfileCache;
}
@@ -44,7 +40,7 @@ public class DefaultTenantRoutingInfoService implements TenantRoutingInfoService
public TenantRoutingInfo getRoutingInfo(TenantId tenantId) {
TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
if (tenantProfile != null) {
- return new TenantRoutingInfo(tenantId, tenantProfile.isIsolatedTbRuleEngine());
+ return new TenantRoutingInfo(tenantId, tenantProfile.getId(), tenantProfile.isIsolatedTbRuleEngine());
} else {
throw new TenantNotFoundException(tenantId);
}
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/queue/TbRuleEngineConsumerStats.java b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java
index 77e805eb62..2904c299ce 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java
@@ -18,6 +18,7 @@ package org.thingsboard.server.service.queue;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.common.stats.StatsCounter;
import org.thingsboard.server.common.stats.StatsFactory;
@@ -63,9 +64,11 @@ public class TbRuleEngineConsumerStats {
private final ConcurrentMap tenantExceptions = new ConcurrentHashMap<>();
private final String queueName;
+ private final TenantId tenantId;
- public TbRuleEngineConsumerStats(String queueName, StatsFactory statsFactory) {
- this.queueName = queueName;
+ public TbRuleEngineConsumerStats(Queue queue, StatsFactory statsFactory) {
+ this.queueName = queue.getName();
+ this.tenantId = queue.getTenantId();
this.statsFactory = statsFactory;
String statsKey = StatsType.RULE_ENGINE.getName() + "." + queueName;
@@ -156,7 +159,11 @@ public class TbRuleEngineConsumerStats {
counters.forEach(counter -> {
stats.append(counter.getName()).append(" = [").append(counter.get()).append("] ");
});
- log.info("[{}] Stats: {}", queueName, stats);
+ if (tenantId.isSysTenantId()) {
+ log.info("[{}] Stats: {}", queueName, stats);
+ } else {
+ log.info("[{}][{}] Stats: {}", queueName, tenantId, stats);
+ }
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java
index 2d517a2213..b59086a350 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java
@@ -68,7 +68,7 @@ public abstract class AbstractConsumerService 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/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java
index 726a5d98f0..3739958e7a 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java
@@ -249,11 +249,11 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
JsonNode prohibitDifferentUrl = generalSettings.getJsonValue().get("prohibitDifferentUrl");
- if (prohibitDifferentUrl != null && prohibitDifferentUrl.asBoolean()) {
+ if ((prohibitDifferentUrl != null && prohibitDifferentUrl.asBoolean()) || httpServletRequest == null) {
baseUrl = generalSettings.getJsonValue().get("baseUrl").asText();
}
- if (StringUtils.isEmpty(baseUrl)) {
+ if (StringUtils.isEmpty(baseUrl) && httpServletRequest != null) {
baseUrl = MiscUtils.constructBaseUrl(httpServletRequest);
}
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..cdc5afe361 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,9 +226,8 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService= deviceState.getLastActivityTime()) {
+ deviceState.setLastInactivityAlarmTime(0L);
+ save(deviceId, INACTIVITY_ALARM_TIME, 0L);
+ }
}
}
}
@@ -533,7 +534,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 +772,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 +812,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..e55fdb17c5 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;
@@ -65,8 +65,9 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
private final TbNotificationEntityService entityNotificationService;
protected static final List SUPPORTED_ENTITY_TYPES = List.of(
- EntityType.CUSTOMER, EntityType.ASSET_PROFILE, EntityType.ASSET, EntityType.RULE_CHAIN,
- EntityType.DASHBOARD, EntityType.DEVICE_PROFILE, EntityType.DEVICE,
+ EntityType.CUSTOMER, EntityType.RULE_CHAIN, EntityType.DASHBOARD,
+ EntityType.ASSET_PROFILE, EntityType.ASSET,
+ EntityType.DEVICE_PROFILE, EntityType.DEVICE,
EntityType.ENTITY_VIEW, EntityType.WIDGETS_BUNDLE,
EntityType.NOTIFICATION_TEMPLATE, EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_RULE
);
@@ -119,8 +120,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/exporting/impl/BaseEntityExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java
index 09b96d68fa..abc90221be 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java
@@ -26,6 +26,7 @@ import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import java.util.Collection;
import java.util.Set;
+import java.util.regex.Pattern;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -47,8 +48,8 @@ public abstract class BaseEntityExportService getSupportedEntityTypes();
- protected void replaceUuidsRecursively(EntitiesExportCtx> ctx, JsonNode node, Set skipFieldsSet) {
- JacksonUtil.replaceUuidsRecursively(node, skipFieldsSet, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid));
+ protected void replaceUuidsRecursively(EntitiesExportCtx> ctx, JsonNode node, Set skipFieldsSet, Pattern includedFieldsPattern) {
+ JacksonUtil.replaceUuidsRecursively(node, skipFieldsSet, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid));
}
protected Stream toExternalIds(Collection internalIds, Function entityIdCreator,
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java
index b408aadd68..0df1e83c7f 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java
@@ -26,7 +26,6 @@ import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
-import java.util.Collections;
import java.util.Set;
@Service
@@ -41,10 +40,10 @@ public class DashboardExportService extends BaseEntityExportService {
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 +267,8 @@ public abstract class BaseEntityImportService skipFieldsSet, LinkedHashSet hints) {
- JacksonUtil.replaceUuidsRecursively(entityAlias, skipFieldsSet,
- uuid -> idProvider.getInternalIdByUuid(uuid, ctx.isFinalImportAttempt(), hints).map(EntityId::getId).orElse(uuid));
+ protected void replaceIdsRecursively(EntitiesImportCtx ctx, IdProvider idProvider, JsonNode json,
+ Set skipFieldsSet, Pattern includedFieldsPattern,
+ LinkedHashSet hints) {
+ JacksonUtil.replaceUuidsRecursively(json, skipFieldsSet, includedFieldsPattern,
+ uuid -> idProvider.getInternalIdByUuid(uuid, ctx.isFinalImportAttempt(), hints)
+ .map(EntityId::getId).orElse(uuid));
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java
index 250026c71c..eac229f774 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java
@@ -65,10 +65,10 @@ public class DashboardImportService extends BaseEntityImportService exportData, IdProvider idProvider) {
for (JsonNode entityAlias : dashboard.getEntityAliasesConfig()) {
- replaceIdsRecursively(ctx, idProvider, entityAlias, Set.of("id"), HINTS);
+ replaceIdsRecursively(ctx, idProvider, entityAlias, Set.of("id"), null, HINTS);
}
for (JsonNode widgetConfig : dashboard.getWidgetsConfig()) {
- replaceIdsRecursively(ctx, idProvider, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Set.of("id"), HINTS);
+ replaceIdsRecursively(ctx, idProvider, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Set.of("id"), null, HINTS);
}
return dashboard;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
index 3cc0310079..70d09f6678 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
@@ -68,8 +68,8 @@ public class DeviceProfileImportService extends BaseEntityImportService {
private static final LinkedHashSet HINTS = new LinkedHashSet<>(Arrays.asList(EntityType.RULE_CHAIN, EntityType.DEVICE, EntityType.ASSET));
+ public static final Pattern PROCESSED_CONFIG_FIELDS_PATTERN = Pattern.compile(".*[iI]d.*");
private final TbRuleChainService tbRuleChainService;
private final RuleChainService ruleChainService;
@@ -92,7 +93,8 @@ public class RuleChainImportService extends BaseEntityImportService replaceIdsRecursively(ctx, idProvider, ruleNode.getConfiguration(), Collections.emptySet(), HINTS));
+ ruleNodes.forEach(ruleNode -> replaceIdsRecursively(ctx, idProvider, ruleNode.getConfiguration(),
+ Collections.emptySet(), PROCESSED_CONFIG_FIELDS_PATTERN, HINTS));
Optional.ofNullable(metaData.getRuleChainConnections()).orElse(Collections.emptyList())
.forEach(ruleChainConnectionInfo -> {
ruleChainConnectionInfo.setTargetRuleChainId(idProvider.getInternalId(ruleChainConnectionInfo.getTargetRuleChainId(), false));
@@ -128,14 +130,12 @@ public class RuleChainImportService extends BaseEntityImportService existingWidgets = widgetTypeService.findWidgetTypesInfosByTenantIdAndBundleAlias(ctx.getTenantId(), savedWidgetsBundle.getAlias()).stream()
- .collect(Collectors.toMap(BaseWidgetType::getAlias, w -> w));
+ .collect(Collectors.toMap(BaseWidgetType::getFqn, w -> w));
for (WidgetTypeDetails widget : exportData.getWidgets()) {
WidgetTypeInfo existingWidget;
- if ((existingWidget = existingWidgets.remove(widget.getAlias())) != null) {
+ if ((existingWidget = existingWidgets.remove(widget.getFqn())) != null) {
widget.setId(existingWidget.getId());
widget.setCreatedTime(existingWidget.getCreatedTime());
} else {
@@ -91,12 +88,6 @@ public class WidgetsBundleImportService extends 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/sync/vc/DefaultGitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
index feff708983..0cc73cd945 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
@@ -103,7 +103,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
private final Map> pendingRequestMap = new HashMap<>();
private final Map> chunkedMsgs = new ConcurrentHashMap<>();
- @Value("${queue.vc.request-timeout:60000}")
+ @Value("${queue.vc.request-timeout:180000}")
private int requestTimeout;
@Value("${queue.vc.msg-chunk-size:500000}")
private int msgChunkSize;
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 7b2296aa13..3a01df9540 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}"
@@ -393,6 +400,10 @@ actors:
queue_size: "${ACTORS_RULE_TRANSACTION_QUEUE_SIZE:15000}"
# Time in milliseconds for transaction to complete
duration: "${ACTORS_RULE_TRANSACTION_DURATION:60000}"
+ external:
+ # Force acknowledgement of the incoming message for external rule nodes to decrease processing latency.
+ # Enqueue the result of external node processing as a separate message to the rule engine.
+ force_ack: "${ACTORS_RULE_EXTERNAL_NODE_FORCE_ACK:false}"
rpc:
max_retries: "${ACTORS_RPC_MAX_RETRIES:5}"
sequential: "${ACTORS_RPC_SEQUENTIAL:false}"
@@ -482,7 +493,7 @@ cache:
timeToLiveInMinutes: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_TTL:60}"
maxSize: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_MAX_SIZE:100000}"
versionControlTask:
- timeToLiveInMinutes: "${CACHE_SPECS_VERSION_CONTROL_TASK_TTL:5}"
+ timeToLiveInMinutes: "${CACHE_SPECS_VERSION_CONTROL_TASK_TTL:20}"
maxSize: "${CACHE_SPECS_VERSION_CONTROL_TASK_MAX_SIZE:100000}"
userSettings:
timeToLiveInMinutes: "${CACHE_SPECS_USER_SETTINGS_TTL:1440}"
@@ -493,6 +504,9 @@ cache:
entityCount:
timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}"
maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}"
+ resourceInfo:
+ timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}"
+ maxSize: "${CACHE_SPECS_RESOURCE_INFO_MAX_SIZE:100000}"
# deliberately placed outside 'specs' group above
notificationRules:
@@ -982,6 +996,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}"
@@ -1052,6 +1095,7 @@ queue:
fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}"
request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms
session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms
+ auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none
use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}"
confluent:
ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}"
@@ -1171,8 +1215,8 @@ queue:
topic: "${TB_QUEUE_VC_TOPIC:tb_version_control}"
partitions: "${TB_QUEUE_VC_PARTITIONS:10}"
poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}"
- pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:60000}"
- request-timeout: "${TB_QUEUE_VC_REQUEST_TIMEOUT:60000}"
+ pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:180000}"
+ request-timeout: "${TB_QUEUE_VC_REQUEST_TIMEOUT:180000}"
msg-chunk-size: "${TB_QUEUE_VC_MSG_CHUNK_SIZE:250000}"
js:
# JS Eval request topic
@@ -1248,6 +1292,8 @@ queue:
failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries.
+ # After a queue is deleted (or profile's isolation option was disabled), Rule Engine will continue reading related topics during this period, before deleting the actual topics
+ topic-deletion-delay: "${TB_QUEUE_RULE_ENGINE_TOPIC_DELETION_DELAY_SEC:30}"
transport:
# For high priority notifications that require minimum latency and processing time
notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}"
@@ -1261,6 +1307,10 @@ service:
type: "${TB_SERVICE_TYPE:monolith}" # monolith or tb-core or tb-rule-engine
# Unique id for this service (autogenerated if empty)
id: "${TB_SERVICE_ID:}"
+ rule_engine:
+ # Comma-separated list of tenant profiles ids assigned to this Rule Engine.
+ # This Rule Engine will only be responsible for tenants with these profiles (in case 'isolation' option is enabled in profile).
+ assigned_tenant_profiles: "${TB_RULE_ENGINE_ASSIGNED_TENANT_PROFILES:}"
metrics:
# Enable/disable actuator metrics.
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..888c9de367 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);
@@ -1012,13 +1029,20 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return (DeviceActorMessageProcessor) ReflectionTestUtils.getField(actor, "processor");
}
- protected void updateDefaultTenantProfile(Consumer updater) throws ThingsboardException {
- TenantProfile tenantProfile = tenantProfileService.findDefaultTenantProfile(TenantId.SYS_TENANT_ID);
- TenantProfileData profileData = tenantProfile.getProfileData();
- DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration) profileData.getConfiguration();
- updater.accept(profileConfiguration);
- tenantProfile.setProfileData(profileData);
- tbTenantProfileService.save(TenantId.SYS_TENANT_ID, tenantProfile, null);
+ protected void updateDefaultTenantProfileConfig(Consumer updater) throws ThingsboardException {
+ updateDefaultTenantProfile(tenantProfile -> {
+ TenantProfileData profileData = tenantProfile.getProfileData();
+ DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration) profileData.getConfiguration();
+ updater.accept(profileConfiguration);
+ tenantProfile.setProfileData(profileData);
+ });
+ }
+
+ protected void updateDefaultTenantProfile(Consumer updater) throws ThingsboardException {
+ TenantProfile oldTenantProfile = tenantProfileService.findDefaultTenantProfile(TenantId.SYS_TENANT_ID);
+ TenantProfile tenantProfile = JacksonUtil.clone(oldTenantProfile);
+ updater.accept(tenantProfile);
+ tbTenantProfileService.save(TenantId.SYS_TENANT_ID, tenantProfile, oldTenantProfile);
}
}
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 05030f0091..36c5eacd36 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java
@@ -32,6 +32,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
@@ -39,6 +40,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.alarm.AlarmDao;
import org.thingsboard.server.dao.service.DaoSqlTest;
@@ -156,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);
@@ -168,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);
@@ -180,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);
@@ -192,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
@@ -239,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);
}
@@ -252,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);
}
@@ -529,6 +540,100 @@ 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();
+
+ 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);
+
+ doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk());
+
+ foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class);
+ Assert.assertNotNull(foundAlarm);
+ Assert.assertNull(foundAlarm.getAssigneeId());
+ Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs);
+ }
+
@Test
public void testFindAlarmsViaCustomerUser() throws Exception {
loginCustomerUser();
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 11d11eccdd..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();
@@ -244,6 +243,53 @@ public class DeviceControllerTest extends AbstractControllerTest {
testNotificationUpdateGatewayOneTime(savedDevice, oldDevice);
}
+ @Test
+ public void testSaveDeviceWithCredentials_CredentialsIsNull() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ device.setType("default");
+
+ SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, null);
+ doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Validation error: credentials must not be null")));
+ }
+
+ @Test
+ public void testSaveDeviceWithCredentials_DeviceIsNull() throws Exception {
+ String testToken = "TEST_TOKEN";
+
+ DeviceCredentials deviceCredentials = new DeviceCredentials();
+ deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
+ deviceCredentials.setCredentialsId(testToken);
+
+ SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(null, deviceCredentials);
+ doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Validation error: device must not be null")));
+ }
+
+ @Test
+ public void testSaveDeviceWithCredentials_WithExistingName() throws Exception {
+ String testToken = "TEST_TOKEN";
+
+ Device device = new Device();
+ device.setName("My device");
+ device.setType("default");
+
+ DeviceCredentials deviceCredentials = new DeviceCredentials();
+ deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
+ deviceCredentials.setCredentialsId(testToken);
+
+ SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, deviceCredentials);
+
+ Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
+
+ Device savedDevice = readResponse(doPost("/api/device-with-credentials", saveRequest).andExpect(status().isOk()), Device.class);
+ Assert.assertNotNull(savedDevice);
+
+ doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Device with such name already exists!")));
+ }
+
@Test
public void saveDeviceWithViolationOfValidation() throws Exception {
Device device = new Device();
@@ -389,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;
@@ -399,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++) {
@@ -444,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);
@@ -464,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();
@@ -504,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();
@@ -519,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();
@@ -543,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();
@@ -558,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();
@@ -795,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);
@@ -818,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();
}
@@ -1005,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);
@@ -1027,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..bdd5f8d352 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;
@@ -46,6 +47,7 @@ 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.id.TenantProfileId;
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,12 +64,17 @@ 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.TenantProfileUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.TenantUpdateMsg;
+import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
@@ -77,6 +84,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 +95,6 @@ public class EdgeControllerTest extends AbstractControllerTest {
private IdComparator