future;
switch (type) {
@@ -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,8 +209,14 @@ 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);
+ log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type);
future = Futures.immediateFuture(null);
}
Futures.addCallback(future, new FutureCallback<>() {
@@ -237,16 +227,16 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
@Override
public void onFailure(Throwable throwable) {
- callBackFailure(edgeNotificationMsg, callback, throwable);
+ callBackFailure(tenantId, edgeNotificationMsg, callback, throwable);
}
}, dbCallBackExecutor);
} catch (Exception e) {
- callBackFailure(edgeNotificationMsg, callback, e);
+ callBackFailure(tenantId, edgeNotificationMsg, callback, e);
}
}
- private void callBackFailure(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) {
- log.error("Can't push to edge updates, edgeNotificationMsg [{}]", edgeNotificationMsg, throwable);
+ private void callBackFailure(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) {
+ log.error("[{}] Can't push to edge updates, edgeNotificationMsg [{}]", tenantId, edgeNotificationMsg, throwable);
callback.onFailure(throwable);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
index 474c7ba233..dc83e0f2a2 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,7 +35,10 @@ 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.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings;
@@ -55,6 +58,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;
@@ -113,6 +118,9 @@ public class EdgeContextComponent {
@Autowired
private CustomerService customerService;
+ @Autowired
+ private WidgetTypeService widgetTypeService;
+
@Autowired
private WidgetsBundleService widgetsBundleService;
@@ -122,6 +130,12 @@ public class EdgeContextComponent {
@Autowired
private OtaPackageService otaPackageService;
+ @Autowired
+ private TenantService tenantService;
+
+ @Autowired
+ private TenantProfileService tenantProfileService;
+
@Autowired
private QueueService queueService;
@@ -179,6 +193,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/instructions/DefaultEdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
index 344a4e6742..fc2dca0655 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
@@ -28,7 +28,6 @@ import org.thingsboard.server.service.install.InstallScripts;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -56,7 +55,20 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
private String appVersion;
@Override
- public EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request) {
+ public EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request) {
+ switch (installationMethod.toLowerCase()) {
+ case "docker":
+ return getDockerInstallInstructions(edge, request);
+ case "ubuntu":
+ return getUbuntuInstallInstructions(edge, request);
+ case "centos":
+ return getCentosInstallInstructions(edge, request);
+ default:
+ throw new IllegalArgumentException("Unsupported installation method for Edge: " + installationMethod);
+ }
+ }
+
+ private EdgeInstallInstructions getDockerInstallInstructions(Edge edge, HttpServletRequest request) {
String dockerInstallInstructions = readFile(resolveFile("docker", "instructions.md"));
String baseUrl = request.getServerName();
if (baseUrl.contains("localhost") || baseUrl.contains("127.0.0.1")) {
@@ -70,16 +82,40 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
String edgeVersion = appVersion + "EDGE";
edgeVersion = edgeVersion.replace("-SNAPSHOT", "");
dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
- dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey());
- dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret());
- dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort));
- dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_RPC_SSL_ENABLED}", Boolean.toString(sslEnabled));
+ dockerInstallInstructions = replacePlaceholders(dockerInstallInstructions, edge);
return new EdgeInstallInstructions(dockerInstallInstructions);
}
+ private EdgeInstallInstructions getUbuntuInstallInstructions(Edge edge, HttpServletRequest request) {
+ String ubuntuInstallInstructions = readFile(resolveFile("ubuntu", "instructions.md"));
+ ubuntuInstallInstructions = replacePlaceholders(ubuntuInstallInstructions, edge);
+ ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${BASE_URL}", request.getServerName());
+ String edgeVersion = appVersion.replace("-SNAPSHOT", "");
+ ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
+ return new EdgeInstallInstructions(ubuntuInstallInstructions);
+ }
+
+
+ private EdgeInstallInstructions getCentosInstallInstructions(Edge edge, HttpServletRequest request) {
+ String centosInstallInstructions = readFile(resolveFile("centos", "instructions.md"));
+ centosInstallInstructions = replacePlaceholders(centosInstallInstructions, edge);
+ centosInstallInstructions = centosInstallInstructions.replace("${BASE_URL}", request.getServerName());
+ String edgeVersion = appVersion.replace("-SNAPSHOT", "");
+ centosInstallInstructions = centosInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
+ return new EdgeInstallInstructions(centosInstallInstructions);
+ }
+
+ private String replacePlaceholders(String instructions, Edge edge) {
+ instructions = instructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey());
+ instructions = instructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret());
+ instructions = instructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort));
+ instructions = instructions.replace("${CLOUD_RPC_SSL_ENABLED}", Boolean.toString(sslEnabled));
+ return instructions;
+ }
+
private String readFile(Path file) {
try {
- return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
+ return Files.readString(file);
} catch (IOException e) {
log.warn("Failed to read file: {}", file, e);
throw new RuntimeException(e);
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
index 52a9a5d820..fa320af68d 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
@@ -23,6 +23,5 @@ import jakarta.servlet.http.HttpServletRequest;
public interface EdgeInstallService {
- EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request);
-
+ EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request);
}
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 91efd0edf7..89cae58264 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")
@@ -198,17 +195,17 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
switch (msg.getMsgType()) {
case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG:
EdgeEventUpdateMsg edgeEventUpdateMsg = (EdgeEventUpdateMsg) msg;
- log.trace("[{}] onToEdgeSessionMsg [{}]", edgeEventUpdateMsg.getTenantId(), msg);
+ log.trace("[{}] onToEdgeSessionMsg [{}]", tenantId, msg);
onEdgeEvent(tenantId, edgeEventUpdateMsg.getEdgeId());
break;
case EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG:
ToEdgeSyncRequest toEdgeSyncRequest = (ToEdgeSyncRequest) msg;
- log.trace("[{}] toEdgeSyncRequest [{}]", toEdgeSyncRequest.getTenantId(), msg);
+ log.trace("[{}] toEdgeSyncRequest [{}]", tenantId, msg);
startSyncProcess(tenantId, toEdgeSyncRequest.getEdgeId(), toEdgeSyncRequest.getId());
break;
case EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG:
FromEdgeSyncResponse fromEdgeSyncResponse = (FromEdgeSyncResponse) msg;
- log.trace("[{}] fromEdgeSyncResponse [{}]", fromEdgeSyncResponse.getTenantId(), msg);
+ log.trace("[{}] fromEdgeSyncResponse [{}]", tenantId, msg);
processSyncResponse(fromEdgeSyncResponse);
break;
}
@@ -266,7 +263,8 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
}
private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) {
- log.info("[{}] edge [{}] connected successfully.", edgeGrpcSession.getSessionId(), edgeId);
+ TenantId tenantId = edgeGrpcSession.getEdge().getTenantId();
+ log.info("[{}][{}] edge [{}] connected successfully.", tenantId, edgeGrpcSession.getSessionId(), edgeId);
sessions.put(edgeId, edgeGrpcSession);
final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock());
newEventLock.lock();
@@ -275,10 +273,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} finally {
newEventLock.unlock();
}
- save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
+ save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
long lastConnectTs = System.currentTimeMillis();
- save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs);
- pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, CONNECT_EVENT);
+ save(tenantId, edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs);
+ pushRuleEngineMessage(tenantId, edgeId, lastConnectTs, TbMsgType.CONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId);
scheduleEdgeEventsCheck(edgeGrpcSession);
}
@@ -337,7 +335,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
newEventLock.lock();
try {
if (Boolean.TRUE.equals(sessionNewEvents.get(edgeId))) {
- log.trace("[{}] Set session new events flag to false", edgeId.getId());
+ log.trace("[{}][{}] Set session new events flag to false", tenantId, edgeId.getId());
sessionNewEvents.put(edgeId, false);
Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() {
@Override
@@ -395,46 +393,49 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} finally {
newEventLock.unlock();
}
- save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);
+ TenantId tenantId = toRemove.getEdge().getTenantId();
+ save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);
long lastDisconnectTs = System.currentTimeMillis();
- save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs);
- pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT);
+ save(tenantId, edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs);
+ 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);
}
}
- private void save(EdgeId edgeId, String key, long value) {
- log.debug("[{}] Updating long edge telemetry [{}] [{}]", edgeId, key, value);
+ private void save(TenantId tenantId, EdgeId edgeId, String key, long value) {
+ log.debug("[{}][{}] Updating long edge telemetry [{}] [{}]", tenantId, edgeId, key, value);
if (persistToTelemetry) {
tsSubService.saveAndNotify(
- TenantId.SYS_TENANT_ID, edgeId,
+ tenantId, edgeId,
Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))),
- new AttributeSaveCallback(edgeId, key, value));
+ new AttributeSaveCallback(tenantId, edgeId, key, value));
} else {
- tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value));
+ tsSubService.saveAttrAndNotify(tenantId, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(tenantId, edgeId, key, value));
}
}
- private void save(EdgeId edgeId, String key, boolean value) {
- log.debug("[{}] Updating boolean edge telemetry [{}] [{}]", edgeId, key, value);
+ private void save(TenantId tenantId, EdgeId edgeId, String key, boolean value) {
+ log.debug("[{}][{}] Updating boolean edge telemetry [{}] [{}]", tenantId, edgeId, key, value);
if (persistToTelemetry) {
tsSubService.saveAndNotify(
- TenantId.SYS_TENANT_ID, edgeId,
+ tenantId, edgeId,
Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))),
- new AttributeSaveCallback(edgeId, key, value));
+ new AttributeSaveCallback(tenantId, edgeId, key, value));
} else {
- tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value));
+ tsSubService.saveAttrAndNotify(tenantId, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(tenantId, edgeId, key, value));
}
}
private static class AttributeSaveCallback implements FutureCallback {
+ private final TenantId tenantId;
private final EdgeId edgeId;
private final String key;
private final Object value;
- AttributeSaveCallback(EdgeId edgeId, String key, Object value) {
+ AttributeSaveCallback(TenantId tenantId, EdgeId edgeId, String key, Object value) {
+ this.tenantId = tenantId;
this.edgeId = edgeId;
this.key = key;
this.value = value;
@@ -442,19 +443,19 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
@Override
public void onSuccess(@Nullable Void result) {
- log.trace("[{}] Successfully updated attribute [{}] with value [{}]", edgeId, key, value);
+ log.trace("[{}][{}] Successfully updated attribute [{}] with value [{}]", tenantId, edgeId, key, value);
}
@Override
public void onFailure(Throwable t) {
- log.warn("[{}] Failed to update attribute [{}] with value [{}]", edgeId, key, value, t);
+ log.warn("[{}][{}] Failed to update attribute [{}] with value [{}]", tenantId, edgeId, key, value, t);
}
}
- private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, String msgType) {
+ private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, TbMsgType msgType) {
try {
ObjectNode edgeState = JacksonUtil.newObjectNode();
- if (msgType.equals(CONNECT_EVENT)) {
+ if (msgType.equals(TbMsgType.CONNECT_EVENT)) {
edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, true);
edgeState.put(DefaultDeviceStateService.LAST_CONNECT_TIME, ts);
} else {
@@ -464,7 +465,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 4f0f5d277a..59d744c3f1 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
@@ -39,12 +39,16 @@ 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;
@@ -53,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;
@@ -100,6 +105,7 @@ public final class EdgeGrpcSession implements Closeable {
private EdgeContextComponent ctx;
private Edge edge;
+ private TenantId tenantId;
private StreamObserver inputStream;
private StreamObserver outputStream;
private boolean connected;
@@ -143,7 +149,7 @@ public final class EdgeGrpcSession implements Closeable {
outputStream.onError(new RuntimeException(responseMsg.getErrorMsg()));
} else {
if (requestMsg.getConnectRequestMsg().hasMaxInboundMessageSize()) {
- log.debug("[{}] Client max inbound message size: {}", sessionId, requestMsg.getConnectRequestMsg().getMaxInboundMessageSize());
+ log.debug("[{}][{}] Client max inbound message size: {}", tenantId, sessionId, requestMsg.getConnectRequestMsg().getMaxInboundMessageSize());
clientMaxInboundMessageSize = requestMsg.getConnectRequestMsg().getMaxInboundMessageSize();
}
connected = true;
@@ -151,8 +157,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();
}
@@ -174,13 +180,13 @@ public final class EdgeGrpcSession implements Closeable {
@Override
public void onError(Throwable t) {
- log.error("[{}] Stream was terminated due to error:", sessionId, t);
+ log.error("[{}][{}] Stream was terminated due to error:", tenantId, sessionId, t);
closeSession();
}
@Override
public void onCompleted() {
- log.info("[{}] Stream was closed and completed successfully!", sessionId);
+ log.info("[{}][{}] Stream was closed and completed successfully!", tenantId, sessionId);
closeSession();
}
@@ -201,7 +207,7 @@ public final class EdgeGrpcSession implements Closeable {
}
public void startSyncProcess(boolean fullSync) {
- log.trace("[{}][{}][{}] Staring edge sync process", edge.getTenantId(), edge.getId(), this.sessionId);
+ log.trace("[{}][{}][{}] Staring edge sync process", this.tenantId, edge.getId(), this.sessionId);
syncCompleted = false;
interruptGeneralProcessingOnSync();
doSync(new EdgeSyncCursor(ctx, edge, fullSync));
@@ -211,7 +217,7 @@ public final class EdgeGrpcSession implements Closeable {
if (cursor.hasNext()) {
EdgeEventFetcher next = cursor.getNext();
log.info("[{}][{}] starting sync process, cursor current idx = {}, class = {}",
- edge.getTenantId(), edge.getId(), cursor.getCurrentIdx(), next.getClass().getSimpleName());
+ this.tenantId, edge.getId(), cursor.getCurrentIdx(), next.getClass().getSimpleName());
ListenableFuture> future = startProcessingEdgeEvents(next);
Futures.addCallback(future, new FutureCallback<>() {
@Override
@@ -221,7 +227,7 @@ public final class EdgeGrpcSession implements Closeable {
@Override
public void onFailure(Throwable t) {
- log.error("[{}][{}] Exception during sync process", edge.getTenantId(), edge.getId(), t);
+ log.error("[{}][{}] Exception during sync process", tenantId, edge.getId(), t);
}
}, ctx.getGrpcCallbackExecutorService());
} else {
@@ -238,7 +244,7 @@ public final class EdgeGrpcSession implements Closeable {
@Override
public void onFailure(Throwable t) {
- log.error("[{}][{}] Exception during sending sync complete", edge.getTenantId(), edge.getId(), t);
+ log.error("[{}][{}] Exception during sending sync complete", tenantId, edge.getId(), t);
}
}, ctx.getGrpcCallbackExecutorService());
}
@@ -274,39 +280,40 @@ public final class EdgeGrpcSession implements Closeable {
try {
if (msg.getSuccess()) {
sessionState.getPendingMsgsMap().remove(msg.getDownlinkMsgId());
- log.debug("[{}] Msg has been processed successfully!Msd Id: [{}], Msg: {}", edge.getRoutingKey(), msg.getDownlinkMsgId(), msg);
+ log.debug("[{}][{}] Msg has been processed successfully!Msg Id: [{}], Msg: {}", this.tenantId, edge.getRoutingKey(), msg.getDownlinkMsgId(), msg);
} else {
- log.error("[{}] Msg processing failed! Msd Id: [{}], Error msg: {}", edge.getRoutingKey(), msg.getDownlinkMsgId(), msg.getErrorMsg());
+ log.error("[{}][{}] Msg processing failed! Msg Id: [{}], Error msg: {}", this.tenantId, edge.getRoutingKey(), msg.getDownlinkMsgId(), msg.getErrorMsg());
}
if (sessionState.getPendingMsgsMap().isEmpty()) {
- log.debug("[{}] Pending msgs map is empty. Stopping current iteration", edge.getRoutingKey());
+ log.debug("[{}][{}] Pending msgs map is empty. Stopping current iteration", this.tenantId, edge.getRoutingKey());
stopCurrentSendDownlinkMsgsTask(false);
}
} catch (Exception e) {
- log.error("[{}] Can't process downlink response message [{}]", this.sessionId, msg, e);
+ log.error("[{}][{}] Can't process downlink response message [{}]", this.tenantId, this.sessionId, msg, e);
}
}
private void sendDownlinkMsg(ResponseMsg downlinkMsg) {
- log.trace("[{}] Sending downlink msg [{}]", this.sessionId, downlinkMsg);
+ log.trace("[{}][{}] Sending downlink msg [{}]", this.tenantId, this.sessionId, downlinkMsg);
if (isConnected()) {
downlinkMsgLock.lock();
try {
outputStream.onNext(downlinkMsg);
} catch (Exception e) {
- log.error("[{}] Failed to send downlink message [{}]", this.sessionId, downlinkMsg, e);
+ log.error("[{}][{}] Failed to send downlink message [{}]", this.tenantId, this.sessionId, downlinkMsg, e);
connected = false;
sessionCloseListener.accept(edge.getId(), sessionId);
} finally {
downlinkMsgLock.unlock();
}
- log.trace("[{}] Response msg successfully sent [{}]", this.sessionId, downlinkMsg);
+ log.trace("[{}][{}] Response msg successfully sent [{}]", this.tenantId, this.sessionId, downlinkMsg);
}
}
void onConfigurationUpdate(Edge edge) {
log.debug("[{}] onConfigurationUpdate [{}]", this.sessionId, edge);
this.edge = edge;
+ this.tenantId = edge.getTenantId();
EdgeUpdateMsg edgeConfig = EdgeUpdateMsg.newBuilder()
.setConfiguration(ctx.getEdgeMsgConstructor().constructEdgeConfiguration(edge)).build();
ResponseMsg edgeConfigMsg = ResponseMsg.newBuilder()
@@ -317,7 +324,7 @@ public final class EdgeGrpcSession implements Closeable {
ListenableFuture processEdgeEvents() throws Exception {
SettableFuture result = SettableFuture.create();
- log.trace("[{}] starting processing edge events", this.sessionId);
+ log.trace("[{}][{}] starting processing edge events", this.tenantId, this.sessionId);
if (isConnected() && isSyncCompleted()) {
Pair startTsAndSeqId = getQueueStartTsAndSeqId().get();
this.previousStartTs = startTsAndSeqId.getFirst();
@@ -337,7 +344,7 @@ public final class EdgeGrpcSession implements Closeable {
Futures.addCallback(updateFuture, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List list) {
- log.debug("[{}] queue offset was updated [{}]", sessionId, newStartTsAndSeqId);
+ log.debug("[{}][{}] queue offset was updated [{}]", tenantId, sessionId, newStartTsAndSeqId);
if (fetcher.isSeqIdNewCycleStarted()) {
seqIdEnd = fetcher.getSeqIdEnd();
boolean newEventsAvailable = isNewEdgeEventsAvailable();
@@ -354,24 +361,24 @@ public final class EdgeGrpcSession implements Closeable {
@Override
public void onFailure(Throwable t) {
- log.error("[{}] Failed to update queue offset [{}]", sessionId, newStartTsAndSeqId, t);
+ log.error("[{}][{}] Failed to update queue offset [{}]", tenantId, sessionId, newStartTsAndSeqId, t);
result.setException(t);
}
}, ctx.getGrpcCallbackExecutorService());
} else {
- log.trace("[{}] newStartTsAndSeqId is null. Skipping iteration without db update", sessionId);
+ log.trace("[{}][{}] newStartTsAndSeqId is null. Skipping iteration without db update", tenantId, sessionId);
result.set(null);
}
}
@Override
public void onFailure(Throwable t) {
- log.error("[{}] Failed to process events", sessionId, t);
+ log.error("[{}][{}] Failed to process events", tenantId, sessionId, t);
result.setException(t);
}
}, ctx.getGrpcCallbackExecutorService());
} else {
- log.trace("[{}] edge is not connected or sync is not completed. Skipping iteration", sessionId);
+ log.trace("[{}][{}] edge is not connected or sync is not completed. Skipping iteration", tenantId, sessionId);
result.set(null);
}
return result;
@@ -388,13 +395,13 @@ public final class EdgeGrpcSession implements Closeable {
try {
PageData pageData = fetcher.fetchEdgeEvents(edge.getTenantId(), edge, pageLink);
if (isConnected() && !pageData.getData().isEmpty()) {
- log.trace("[{}] [{}] event(s) are going to be processed.", this.sessionId, pageData.getData().size());
+ log.trace("[{}][{}][{}] event(s) are going to be processed.", this.tenantId, this.sessionId, pageData.getData().size());
List downlinkMsgsPack = convertToDownlinkMsgsPack(pageData.getData());
Futures.addCallback(sendDownlinkMsgsPack(downlinkMsgsPack), new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Boolean isInterrupted) {
if (Boolean.TRUE.equals(isInterrupted)) {
- log.debug("[{}][{}][{}] Send downlink messages task was interrupted", edge.getTenantId(), edge.getId(), sessionId);
+ log.debug("[{}][{}][{}] Send downlink messages task was interrupted", tenantId, edge.getId(), sessionId);
result.set(null);
} else {
if (isConnected() && pageData.hasNext()) {
@@ -447,14 +454,14 @@ public final class EdgeGrpcSession implements Closeable {
if (isConnected() && sessionState.getPendingMsgsMap().values().size() > 0) {
List copy = new ArrayList<>(sessionState.getPendingMsgsMap().values());
if (attempt > 1) {
- log.warn("[{}] Failed to deliver the batch: {}, attempt: {}", this.sessionId, copy, attempt);
+ log.warn("[{}][{}] Failed to deliver the batch: {}, attempt: {}", this.tenantId, this.sessionId, copy, attempt);
}
- log.trace("[{}] [{}] downlink msg(s) are going to be send.", this.sessionId, copy.size());
+ log.trace("[{}][{}][{}] downlink msg(s) are going to be send.", this.tenantId, this.sessionId, copy.size());
for (DownlinkMsg downlinkMsg : copy) {
if (this.clientMaxInboundMessageSize != 0 && downlinkMsg.getSerializedSize() > this.clientMaxInboundMessageSize) {
log.error("[{}][{}][{}] Downlink msg size [{}] exceeds client max inbound message size [{}]. Skipping this message. " +
"Please increase value of CLOUD_RPC_MAX_INBOUND_MESSAGE_SIZE env variable on the edge and restart it." +
- "Message {}", edge.getTenantId(), edge.getId(), this.sessionId, downlinkMsg.getSerializedSize(),
+ "Message {}", this.tenantId, edge.getId(), this.sessionId, downlinkMsg.getSerializedSize(),
this.clientMaxInboundMessageSize, downlinkMsg);
sessionState.getPendingMsgsMap().remove(downlinkMsg.getDownlinkMsgId());
} else {
@@ -466,15 +473,15 @@ public final class EdgeGrpcSession implements Closeable {
if (attempt < MAX_DOWNLINK_ATTEMPTS) {
scheduleDownlinkMsgsPackSend(attempt + 1);
} else {
- log.warn("[{}] Failed to deliver the batch after {} attempts. Next messages are going to be discarded {}",
- this.sessionId, MAX_DOWNLINK_ATTEMPTS, copy);
+ log.warn("[{}][{}] Failed to deliver the batch after {} attempts. Next messages are going to be discarded {}",
+ this.tenantId, this.sessionId, MAX_DOWNLINK_ATTEMPTS, copy);
stopCurrentSendDownlinkMsgsTask(false);
}
} else {
stopCurrentSendDownlinkMsgsTask(false);
}
} catch (Exception e) {
- log.warn("[{}] Failed to send downlink msgs. Error msg {}", this.sessionId, e.getMessage(), e);
+ log.warn("[{}][{}] Failed to send downlink msgs. Error msg {}", this.tenantId, this.sessionId, e.getMessage(), e);
stopCurrentSendDownlinkMsgsTask(true);
}
};
@@ -494,7 +501,7 @@ public final class EdgeGrpcSession implements Closeable {
private List convertToDownlinkMsgsPack(List edgeEvents) {
List result = new ArrayList<>();
for (EdgeEvent edgeEvent : edgeEvents) {
- log.trace("[{}][{}] converting edge event to downlink msg [{}]", edge.getTenantId(), this.sessionId, edgeEvent);
+ log.trace("[{}][{}] converting edge event to downlink msg [{}]", this.tenantId, this.sessionId, edgeEvent);
DownlinkMsg downlinkMsg = null;
try {
switch (edgeEvent.getAction()) {
@@ -513,7 +520,7 @@ public final class EdgeGrpcSession implements Closeable {
case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER:
downlinkMsg = convertEntityEventToDownlink(edgeEvent);
- log.trace("[{}][{}] entity message processed [{}]", edgeEvent.getTenantId(), this.sessionId, downlinkMsg);
+ log.trace("[{}][{}] entity message processed [{}]", this.tenantId, this.sessionId, downlinkMsg);
break;
case ATTRIBUTES_UPDATED:
case POST_ATTRIBUTES:
@@ -522,10 +529,10 @@ public final class EdgeGrpcSession implements Closeable {
downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent);
break;
default:
- log.warn("[{}][{}] Unsupported action type [{}]", edge.getTenantId(), this.sessionId, edgeEvent.getAction());
+ log.warn("[{}][{}] Unsupported action type [{}]", this.tenantId, this.sessionId, edgeEvent.getAction());
}
} catch (Exception e) {
- log.error("[{}][{}] Exception during converting edge event to downlink msg", edge.getTenantId(), this.sessionId, e);
+ log.error("[{}][{}] Exception during converting edge event to downlink msg", this.tenantId, this.sessionId, e);
}
if (downlinkMsg != null) {
result.add(downlinkMsg);
@@ -561,7 +568,7 @@ public final class EdgeGrpcSession implements Closeable {
PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), 0L, this.previousStartSeqId == 0 ? null : this.previousStartSeqId - 1, pageLink);
return !edgeEvents.getData().isEmpty();
} catch (Exception e) {
- log.error("[{}][{}][{}] Failed to execute isSeqIdStartedNewCycle", edge.getTenantId(), edge.getId(), sessionId, e);
+ log.error("[{}][{}][{}] Failed to execute isSeqIdStartedNewCycle", this.tenantId, edge.getId(), sessionId, e);
}
return false;
}
@@ -572,7 +579,7 @@ public final class EdgeGrpcSession implements Closeable {
PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), this.newStartSeqId, null, pageLink);
return !edgeEvents.getData().isEmpty();
} catch (Exception e) {
- log.error("[{}][{}][{}] Failed to execute isNewEdgeEventsAvailable", edge.getTenantId(), edge.getId(), sessionId, e);
+ log.error("[{}][{}][{}] Failed to execute isNewEdgeEventsAvailable", this.tenantId, edge.getId(), sessionId, e);
}
return false;
}
@@ -586,7 +593,7 @@ public final class EdgeGrpcSession implements Closeable {
startSeqId = edgeEvents.getData().get(0).getSeqId() - 1;
}
} catch (Exception e) {
- log.error("[{}][{}][{}] Failed to execute findStartSeqIdFromOldestEventIfAny", edge.getTenantId(), edge.getId(), sessionId, e);
+ log.error("[{}][{}][{}] Failed to execute findStartSeqIdFromOldestEventIfAny", this.tenantId, edge.getId(), sessionId, e);
}
return startSeqId;
}
@@ -602,18 +609,18 @@ public final class EdgeGrpcSession implements Closeable {
}
private DownlinkMsg convertEntityEventToDownlink(EdgeEvent edgeEvent) {
- log.trace("Executing convertEntityEventToDownlink, edgeEvent [{}], action [{}]", edgeEvent, edgeEvent.getAction());
+ log.trace("[{}] Executing convertEntityEventToDownlink, edgeEvent [{}], action [{}]", this.tenantId, edgeEvent, edgeEvent.getAction());
switch (edgeEvent.getType()) {
case EDGE:
return ctx.getEdgeProcessor().convertEdgeEventToDownlink(edgeEvent);
case DEVICE:
- return ctx.getDeviceProcessor().convertDeviceEventToDownlink(edgeEvent);
+ return ctx.getDeviceProcessor().convertDeviceEventToDownlink(edgeEvent, this.edge.getId(), this.edgeVersion);
case DEVICE_PROFILE:
- return ctx.getDeviceProfileProcessor().convertDeviceProfileEventToDownlink(edgeEvent);
+ return ctx.getDeviceProfileProcessor().convertDeviceProfileEventToDownlink(edgeEvent, this.edge.getId(), this.edgeVersion);
case ASSET_PROFILE:
- return ctx.getAssetProfileProcessor().convertAssetProfileEventToDownlink(edgeEvent);
+ return ctx.getAssetProfileProcessor().convertAssetProfileEventToDownlink(edgeEvent, this.edge.getId(), this.edgeVersion);
case ASSET:
- return ctx.getAssetProcessor().convertAssetEventToDownlink(edgeEvent);
+ return ctx.getAssetProcessor().convertAssetEventToDownlink(edgeEvent, this.edge.getId(), this.edgeVersion);
case ENTITY_VIEW:
return ctx.getEntityViewProcessor().convertEntityViewEventToDownlink(edgeEvent);
case DASHBOARD:
@@ -640,8 +647,12 @@ 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);
+ log.warn("[{}] Unsupported edge event type [{}]", this.tenantId, edgeEvent);
return null;
}
}
@@ -654,6 +665,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));
@@ -664,16 +680,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));
@@ -715,7 +751,7 @@ public final class EdgeGrpcSession implements Closeable {
}
}
} catch (Exception e) {
- log.error("[{}] Can't process uplink msg [{}]", this.sessionId, uplinkMsg, e);
+ log.error("[{}][{}] Can't process uplink msg [{}]", this.tenantId, this.sessionId, uplinkMsg, e);
return Futures.immediateFailedFuture(e);
}
return Futures.allAsList(result);
@@ -726,6 +762,7 @@ public final class EdgeGrpcSession implements Closeable {
Optional optional = ctx.getEdgeService().findEdgeByRoutingKey(TenantId.SYS_TENANT_ID, request.getEdgeRoutingKey());
if (optional.isPresent()) {
edge = optional.get();
+ this.tenantId = edge.getTenantId();
try {
if (edge.getSecret().equals(request.getEdgeSecret())) {
sessionOpenListener.accept(edge.getId(), this);
@@ -757,25 +794,25 @@ public final class EdgeGrpcSession implements Closeable {
@Override
public void close() {
- log.debug("[{}] Closing session", sessionId);
+ log.debug("[{}][{}] Closing session", this.tenantId, sessionId);
connected = false;
try {
outputStream.onCompleted();
} catch (Exception e) {
- log.debug("[{}] Failed to close output stream: {}", sessionId, e.getMessage());
+ log.debug("[{}][{}] Failed to close output stream: {}", this.tenantId, sessionId, e.getMessage());
}
}
private void interruptPreviousSendDownlinkMsgsTask() {
if (sessionState.getSendDownlinkMsgsFuture() != null && !sessionState.getSendDownlinkMsgsFuture().isDone()
|| sessionState.getScheduledSendDownlinkTask() != null && !sessionState.getScheduledSendDownlinkTask().isCancelled()) {
- log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", edge.getTenantId(), edge.getId(), this.sessionId);
+ log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", this.tenantId, edge.getId(), this.sessionId);
stopCurrentSendDownlinkMsgsTask(true);
}
}
private void interruptGeneralProcessingOnSync() {
- log.debug("[{}][{}][{}] Sync process started. General processing interrupted!", edge.getTenantId(), edge.getId(), this.sessionId);
+ log.debug("[{}][{}][{}] Sync process started. General processing interrupted!", this.tenantId, edge.getId(), this.sessionId);
stopCurrentSendDownlinkMsgsTask(true);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
index bf3e804f7e..4eea16286f 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
@@ -25,6 +25,7 @@ import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.CustomerEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher;
+import org.thingsboard.server.service.edge.rpc.fetch.DefaultProfilesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.DevicesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.EdgeEventFetcher;
@@ -32,8 +33,11 @@ import org.thingsboard.server.service.edge.rpc.fetch.EntityViewsEdgeEventFetcher
import org.thingsboard.server.service.edge.rpc.fetch.OtaPackagesEdgeEventFetcher;
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.SystemWidgetTypesEdgeEventFetcher;
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.TenantWidgetTypesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.TenantWidgetsBundlesEdgeEventFetcher;
import java.util.LinkedList;
@@ -48,11 +52,10 @@ public class EdgeSyncCursor {
public EdgeSyncCursor(EdgeContextComponent ctx, Edge edge, boolean fullSync) {
if (fullSync) {
+ fetchers.add(new TenantEdgeEventFetcher(ctx.getTenantService()));
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 TenantAdminUsersEdgeEventFetcher(ctx.getUserService()));
Customer publicCustomer = ctx.getCustomerService().findOrCreatePublicCustomer(edge.getTenantId());
fetchers.add(new CustomerEdgeEventFetcher(publicCustomer.getId()));
@@ -61,11 +64,16 @@ public class EdgeSyncCursor {
fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId()));
}
}
+ fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
+ fetchers.add(new DefaultProfilesEdgeEventFetcher(ctx.getDeviceProfileService(), ctx.getAssetProfileService()));
+ fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService()));
+ fetchers.add(new AssetProfilesEdgeEventFetcher(ctx.getAssetProfileService()));
fetchers.add(new DevicesEdgeEventFetcher(ctx.getDeviceService()));
fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService()));
fetchers.add(new EntityViewsEdgeEventFetcher(ctx.getEntityViewService()));
- fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
if (fullSync) {
+ fetchers.add(new SystemWidgetTypesEdgeEventFetcher(ctx.getWidgetTypeService()));
+ fetchers.add(new TenantWidgetTypesEdgeEventFetcher(ctx.getWidgetTypeService()));
fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new OtaPackagesEdgeEventFetcher(ctx.getOtaPackageService()));
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
index 447a73e5cf..15d7c27ff6 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
@@ -15,20 +15,9 @@
*/
package org.thingsboard.server.service.edge.rpc.constructor;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
-import org.thingsboard.server.common.data.Device;
-import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.alarm.Alarm;
-import org.thingsboard.server.common.data.asset.Asset;
-import org.thingsboard.server.common.data.id.AssetId;
-import org.thingsboard.server.common.data.id.DeviceId;
-import org.thingsboard.server.common.data.id.EntityViewId;
-import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.dao.asset.AssetService;
-import org.thingsboard.server.dao.device.DeviceService;
-import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
@@ -37,37 +26,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
@TbCoreComponent
public class AlarmMsgConstructor {
- @Autowired
- private DeviceService deviceService;
-
- @Autowired
- private AssetService assetService;
-
- @Autowired
- private EntityViewService entityViewService;
-
- public AlarmUpdateMsg constructAlarmUpdatedMsg(TenantId tenantId, UpdateMsgType msgType, Alarm alarm) {
- String entityName = null;
- switch (alarm.getOriginator().getEntityType()) {
- case DEVICE:
- Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId()));
- if (deviceById != null) {
- entityName = deviceById.getName();
- }
- break;
- case ASSET:
- Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId()));
- if (assetById != null) {
- entityName = assetById.getName();
- }
- break;
- case ENTITY_VIEW:
- EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId()));
- if (entityViewById != null) {
- entityName = entityViewById.getName();
- }
- break;
- }
+ public AlarmUpdateMsg constructAlarmUpdatedMsg(UpdateMsgType msgType, Alarm alarm, String entityName) {
AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(alarm.getId().getId().getMostSignificantBits())
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java
index edfdefb603..50c2b46891 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java
@@ -33,10 +33,17 @@ public class DashboardMsgConstructor {
.setIdMSB(dashboard.getId().getId().getMostSignificantBits())
.setIdLSB(dashboard.getId().getId().getLeastSignificantBits())
.setTitle(dashboard.getTitle())
- .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration()));
+ .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration()))
+ .setMobileHide(dashboard.isMobileHide());
if (dashboard.getAssignedCustomers() != null) {
builder.setAssignedCustomers(JacksonUtil.toString(dashboard.getAssignedCustomers()));
}
+ if (dashboard.getImage() != null) {
+ builder.setImage(dashboard.getImage());
+ }
+ if (dashboard.getMobileOrder() != null) {
+ builder.setMobileOrder(dashboard.getMobileOrder());
+ }
return builder.build();
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java
index 0cef8f3581..a8ff4ffa1a 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java
@@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.adaptor.JsonConverter;
import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg;
import org.thingsboard.server.gen.edge.v1.EntityDataProto;
@@ -40,7 +41,7 @@ import java.util.List;
@TbCoreComponent
public class EntityDataMsgConstructor {
- public EntityDataProto constructEntityDataMsg(EntityId entityId, EdgeEventActionType actionType, JsonElement entityData) {
+ public EntityDataProto constructEntityDataMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType actionType, JsonElement entityData) {
EntityDataProto.Builder builder = EntityDataProto.newBuilder()
.setEntityIdMSB(entityId.getId().getMostSignificantBits())
.setEntityIdLSB(entityId.getId().getLeastSignificantBits())
@@ -57,7 +58,7 @@ public class EntityDataMsgConstructor {
}
builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(data.getAsJsonObject("data"), ts));
} catch (Exception e) {
- log.warn("[{}] Can't convert to telemetry proto, entityData [{}]", entityId, entityData, e);
+ log.warn("[{}][{}] Can't convert to telemetry proto, entityData [{}]", tenantId, entityId, entityData, e);
}
break;
case ATTRIBUTES_UPDATED:
@@ -67,7 +68,7 @@ public class EntityDataMsgConstructor {
builder.setAttributesUpdatedMsg(attributesUpdatedMsg);
builder.setPostAttributeScope(getScopeOfDefault(data));
} catch (Exception e) {
- log.warn("[{}] Can't convert to AttributesUpdatedMsg proto, entityData [{}]", entityId, entityData, e);
+ log.warn("[{}][{}] Can't convert to AttributesUpdatedMsg proto, entityData [{}]", tenantId, entityId, entityData, e);
}
break;
case POST_ATTRIBUTES:
@@ -77,7 +78,7 @@ public class EntityDataMsgConstructor {
builder.setPostAttributesMsg(postAttributesMsg);
builder.setPostAttributeScope(getScopeOfDefault(data));
} catch (Exception e) {
- log.warn("[{}] Can't convert to PostAttributesMsg, entityData [{}]", entityId, entityData, e);
+ log.warn("[{}][{}] Can't convert to PostAttributesMsg, entityData [{}]", tenantId, entityId, entityData, e);
}
break;
case ATTRIBUTES_DELETED:
@@ -90,7 +91,7 @@ public class EntityDataMsgConstructor {
attributeDeleteMsg.build();
builder.setAttributeDeleteMsg(attributeDeleteMsg);
} catch (Exception e) {
- log.warn("[{}] Can't convert to AttributeDeleteMsg proto, entityData [{}]", entityId, entityData, e);
+ log.warn("[{}][{}] Can't convert to AttributeDeleteMsg proto, entityData [{}]", tenantId, entityId, entityData, e);
}
break;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/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..af574b4b75 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
@@ -33,11 +33,15 @@ public class WidgetTypeMsgConstructor {
.setMsgType(msgType)
.setIdMSB(widgetTypeDetails.getId().getId().getMostSignificantBits())
.setIdLSB(widgetTypeDetails.getId().getId().getLeastSignificantBits());
- 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.getFqn().contains(".")) {
+ String[] aliases = widgetTypeDetails.getFqn().split("\\.", 2);
+ if (aliases.length == 2) {
+ builder.setBundleAlias(aliases[0]);
+ builder.setAlias(aliases[1]);
+ }
+ }
}
if (widgetTypeDetails.getName() != null) {
builder.setName(widgetTypeDetails.getName());
@@ -54,6 +58,7 @@ public class WidgetTypeMsgConstructor {
if (widgetTypeDetails.getDescription() != null) {
builder.setDescription(widgetTypeDetails.getDescription());
}
+ builder.setDeprecated(widgetTypeDetails.isDeprecated());
return builder.build();
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java
index 36e43b9579..bed83c8832 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.constructor;
import com.google.protobuf.ByteString;
import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
@@ -25,12 +26,13 @@ import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.nio.charset.StandardCharsets;
+import java.util.List;
@Component
@TbCoreComponent
public class WidgetsBundleMsgConstructor {
- public WidgetsBundleUpdateMsg constructWidgetsBundleUpdateMsg(UpdateMsgType msgType, WidgetsBundle widgetsBundle) {
+ public WidgetsBundleUpdateMsg constructWidgetsBundleUpdateMsg(UpdateMsgType msgType, WidgetsBundle widgetsBundle, List widgets) {
WidgetsBundleUpdateMsg.Builder builder = WidgetsBundleUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(widgetsBundle.getId().getId().getMostSignificantBits())
@@ -46,6 +48,7 @@ public class WidgetsBundleMsgConstructor {
if (widgetsBundle.getTenantId().equals(TenantId.SYS_TENANT_ID)) {
builder.setIsSystem(true);
}
+ builder.setWidgets(JacksonUtil.toString(widgets));
return builder.build();
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
index 28c1b1c458..f33f0f84e8 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
@@ -51,7 +51,7 @@ public abstract class AbstractRuleChainMetadataConstructor implements RuleChainM
builder.setMsgType(msgType);
return builder.build();
} catch (JsonProcessingException ex) {
- log.error("Can't construct RuleChainMetadataUpdateMsg", ex);
+ log.error("[{}] Can't construct RuleChainMetadataUpdateMsg", tenantId, ex);
}
return null;
}
@@ -97,6 +97,8 @@ public abstract class AbstractRuleChainMetadataConstructor implements RuleChainM
.setDebugMode(node.isDebugMode())
.setConfiguration(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getConfiguration()))
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getAdditionalInfo()))
+ .setSingletonMode(node.isSingletonMode())
+ .setConfigurationVersion(node.getConfigurationVersion())
.build();
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
index cefeb4c46a..b9fc1c8c9e 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
@@ -85,7 +85,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, JacksonUtil.OBJECT_MAPPER.valueToTree(tenantMailSettings)));
- AdminSettings systemMailTemplates = loadMailTemplates();
+ AdminSettings systemMailTemplates = loadMailTemplates(tenantId);
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, JacksonUtil.OBJECT_MAPPER.valueToTree(systemMailTemplates)));
@@ -97,7 +97,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
return new PageData<>(result, 1, result.size(), false);
}
- private AdminSettings loadMailTemplates() throws Exception {
+ private AdminSettings loadMailTemplates(TenantId tenantId) throws Exception {
Map mailTemplates = new HashMap<>();
for (String templatesName : templatesNames) {
Template template = freemarkerConfig.getTemplate(templatesName);
@@ -107,7 +107,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
if (mailTemplate != null) {
mailTemplates.put(name, mailTemplate);
} else {
- log.error("Can't load mail template from file {}", template.getName());
+ log.error("[{}] Can't load mail template from file {}", tenantId, template.getName());
}
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetTypesEdgeEventFetcher.java
new file mode 100644
index 0000000000..05d9071ed3
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetTypesEdgeEventFetcher.java
@@ -0,0 +1,52 @@
+/**
+ * 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.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.common.data.widget.WidgetTypeDetails;
+import org.thingsboard.server.common.data.widget.WidgetTypeInfo;
+import org.thingsboard.server.common.data.widget.WidgetsBundle;
+import org.thingsboard.server.dao.widget.WidgetTypeService;
+import org.thingsboard.server.dao.widget.WidgetsBundleService;
+
+@Slf4j
+@AllArgsConstructor
+public abstract class BaseWidgetTypesEdgeEventFetcher extends BasePageableEdgeEventFetcher {
+
+ protected final WidgetTypeService widgetTypeService;
+
+ @Override
+ PageData fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) {
+ return findWidgetTypes(tenantId, pageLink);
+ }
+
+ @Override
+ EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, WidgetTypeInfo widgetTypeInfo) {
+ return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE,
+ EdgeEventActionType.ADDED, widgetTypeInfo.getId(), null);
+ }
+
+ protected abstract PageData findWidgetTypes(TenantId tenantId, PageLink pageLink);
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java
new file mode 100644
index 0000000000..1b4897dfff
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DefaultProfilesEdgeEventFetcher.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.fetch;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.DeviceProfile;
+import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.asset.AssetProfile;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.dao.asset.AssetProfileService;
+import org.thingsboard.server.dao.device.DeviceProfileService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@AllArgsConstructor
+@Slf4j
+public class DefaultProfilesEdgeEventFetcher implements EdgeEventFetcher {
+
+ private final DeviceProfileService deviceProfileService;
+ private final AssetProfileService assetProfileService;
+
+ @Override
+ public PageLink getPageLink(int pageSize) {
+ return null;
+ }
+
+ @Override
+ public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) {
+ List result = new ArrayList<>();
+
+ DeviceProfile deviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId);
+ result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE,
+ EdgeEventActionType.ADDED, deviceProfile.getId(), null));
+
+ AssetProfile assetProfile = assetProfileService.findDefaultAssetProfile(tenantId);
+ result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET_PROFILE,
+ EdgeEventActionType.ADDED, assetProfile.getId(), null));
+
+ return new PageData<>(result, 1, result.size(), false);
+ }
+}
\ No newline at end of file
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java
new file mode 100644
index 0000000000..de4218fc53
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java
@@ -0,0 +1,36 @@
+/**
+ * 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.extern.slf4j.Slf4j;
+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.widget.WidgetTypeInfo;
+import org.thingsboard.server.dao.widget.WidgetTypeService;
+
+@Slf4j
+public class SystemWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventFetcher {
+
+ public SystemWidgetTypesEdgeEventFetcher(WidgetTypeService widgetTypeService) {
+ super(widgetTypeService);
+ }
+
+ @Override
+ protected PageData findWidgetTypes(TenantId tenantId, PageLink pageLink) {
+ return widgetTypeService.findSystemWidgetTypesByPageLink(tenantId, false, pageLink);
+ }
+}
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/fetch/TenantWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java
new file mode 100644
index 0000000000..24f0527c20
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java
@@ -0,0 +1,35 @@
+/**
+ * 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.extern.slf4j.Slf4j;
+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.widget.WidgetTypeInfo;
+import org.thingsboard.server.dao.widget.WidgetTypeService;
+
+@Slf4j
+public class TenantWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventFetcher {
+
+ public TenantWidgetTypesEdgeEventFetcher(WidgetTypeService widgetTypeService) {
+ super(widgetTypeService);
+ }
+ @Override
+ protected PageData findWidgetTypes(TenantId tenantId, PageLink pageLink) {
+ return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(tenantId, false, pageLink);
+ }
+}
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..328a64efe2 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;
@@ -40,10 +46,16 @@ import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.common.data.relation.EntityRelation;
+import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.asset.AssetService;
@@ -55,18 +67,23 @@ 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;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
+import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
+import org.thingsboard.server.queue.TbQueueCallback;
+import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.service.edge.rpc.constructor.AdminSettingsMsgConstructor;
@@ -84,6 +101,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 +123,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 +160,9 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected TenantService tenantService;
+ @Autowired
+ protected TenantProfileService tenantProfileService;
+
@Autowired
protected EdgeService edgeService;
@@ -195,6 +218,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 +272,12 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected AssetProfileMsgConstructor assetProfileMsgConstructor;
+ @Autowired
+ protected TenantMsgConstructor tenantMsgConstructor;
+
+ @Autowired
+ protected TenantProfileMsgConstructor tenantProfileMsgConstructor;
+
@Autowired
protected WidgetsBundleMsgConstructor widgetsBundleMsgConstructor;
@@ -249,15 +293,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 +335,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 +387,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 +438,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 +489,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 +562,92 @@ 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 getEdgeActionTbMsgMetaData(Edge edge, CustomerId customerId) {
+ TbMsgMetaData metaData = new TbMsgMetaData();
+ metaData.putValue("edgeId", edge.getId().toString());
+ metaData.putValue("edgeName", edge.getName());
+ if (customerId != null && !customerId.isNullUid()) {
+ metaData.putValue("customerId", customerId.toString());
+ }
+ return metaData;
+ }
+
+ protected void pushEntityEventToRuleEngine(TenantId tenantId, EntityId entityId, CustomerId customerId,
+ TbMsgType msgType, String msgData, TbMsgMetaData metaData) {
+ TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, msgData);
+ tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, new TbQueueCallback() {
+ @Override
+ public void onSuccess(TbQueueMsgMetadata metadata) {
+ log.debug("[{}] Successfully send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, msgData);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("[{}] Failed to send ENTITY_CREATED EVENT to rule engine [{}]", tenantId, msgData, t);
+ }
+ });
+ }
+
+ protected AssetProfile checkIfAssetProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, AssetProfile assetProfile, EdgeVersion edgeVersion) {
+ switch (edgeVersion) {
+ case V_3_3_3:
+ case V_3_3_0:
+ case V_3_4_0:
+ if (assetProfile.getDefaultDashboardId() != null
+ && isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultDashboardId(), edgeId)) {
+ assetProfile.setDefaultDashboardId(null);
+ }
+ if (assetProfile.getDefaultEdgeRuleChainId() != null
+ && isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultEdgeRuleChainId(), edgeId)) {
+ assetProfile.setDefaultEdgeRuleChainId(null);
+ }
+ break;
+ }
+ return assetProfile;
+ }
+
+ protected DeviceProfile checkIfDeviceProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, DeviceProfile deviceProfile, EdgeVersion edgeVersion) {
+ switch (edgeVersion) {
+ case V_3_3_3:
+ case V_3_3_0:
+ case V_3_4_0:
+ if (deviceProfile.getDefaultDashboardId() != null
+ && isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultDashboardId(), edgeId)) {
+ deviceProfile.setDefaultDashboardId(null);
+ }
+ if (deviceProfile.getDefaultEdgeRuleChainId() != null
+ && isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultEdgeRuleChainId(), edgeId)) {
+ deviceProfile.setDefaultEdgeRuleChainId(null);
+ }
+ break;
+ }
+ return deviceProfile;
+ }
+
+ private boolean isEntityNotAssignedToEdge(TenantId tenantId, EntityId entityId, EdgeId edgeId) {
+ PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
+ PageData pageData;
+ do {
+ pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
+ if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
+ if (pageData.getData().contains(edgeId)) {
+ return false;
+ }
+ if (pageData.hasNext()) {
+ pageLink = pageLink.nextPageLink();
+ }
+ }
+ } while (pageData != null && pageData.hasNext());
+ return true;
+ }
}
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..de072a48e9 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java
@@ -20,15 +20,21 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest;
+import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.AlarmId;
+import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
@@ -45,10 +51,11 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
EntityType.valueOf(alarmUpdateMsg.getOriginatorType()));
AlarmId alarmId = new AlarmId(new UUID(alarmUpdateMsg.getIdMSB(), alarmUpdateMsg.getIdLSB()));
if (originatorId == null) {
- log.warn("Originator not found for the alarm msg {}", alarmUpdateMsg);
+ log.warn("[{}] Originator not found for the alarm msg {}", tenantId, alarmUpdateMsg);
return Futures.immediateFuture(null);
}
try {
+ edgeSynchronizationManager.getSync().set(true);
switch (alarmUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
@@ -72,26 +79,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 +106,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) {
@@ -125,13 +135,38 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor {
case ALARM_CLEAR:
Alarm alarm = alarmService.findAlarmById(tenantId, alarmId);
if (alarm != null) {
- return alarmMsgConstructor.constructAlarmUpdatedMsg(tenantId, msgType, alarm);
+ return alarmMsgConstructor.constructAlarmUpdatedMsg(msgType, alarm, findOriginatorEntityName(tenantId, alarm));
}
break;
case DELETED:
Alarm deletedAlarm = JacksonUtil.OBJECT_MAPPER.convertValue(body, Alarm.class);
- return alarmMsgConstructor.constructAlarmUpdatedMsg(tenantId, msgType, deletedAlarm);
+ return alarmMsgConstructor.constructAlarmUpdatedMsg(msgType, deletedAlarm, findOriginatorEntityName(tenantId, deletedAlarm));
}
return null;
}
+
+ private String findOriginatorEntityName(TenantId tenantId, Alarm alarm) {
+ String entityName = null;
+ switch (alarm.getOriginator().getEntityType()) {
+ case DEVICE:
+ Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId()));
+ if (deviceById != null) {
+ entityName = deviceById.getName();
+ }
+ break;
+ case ASSET:
+ Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId()));
+ if (assetById != null) {
+ entityName = assetById.getName();
+ }
+ break;
+ case ENTITY_VIEW:
+ EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId()));
+ if (entityViewById != null) {
+ entityName = entityViewById.getName();
+ }
+ break;
+ }
+ return entityName;
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java
index 2fb7320219..6e3c56d3b3 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,28 +15,100 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.asset;
+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.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.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
+import org.thingsboard.server.dao.asset.BaseAssetService;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
+import org.thingsboard.server.gen.edge.v1.EdgeVersion;
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;
+
+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();
+ }
+ }
- public DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent) {
+ 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);
+ String assetAsString = JacksonUtil.toString(asset);
+ TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, asset.getCustomerId());
+ pushEntityEventToRuleEngine(tenantId, assetId, asset.getCustomerId(), TbMsgType.ENTITY_CREATED, assetAsString, msgMetaData);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to push asset action to rule engine: {}", tenantId, assetId, TbMsgType.ENTITY_CREATED.name(), e);
+ }
+ }
+
+ public DownlinkMsg convertAssetEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
AssetId assetId = new AssetId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
@@ -46,7 +118,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);
@@ -55,6 +127,7 @@ public class AssetEdgeProcessor extends BaseEdgeProcessor {
.addAssetUpdateMsg(assetUpdateMsg);
if (UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) {
AssetProfile assetProfile = assetProfileService.findAssetProfileById(edgeEvent.getTenantId(), asset.getAssetProfileId());
+ assetProfile = checkIfAssetProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, assetProfile, edgeVersion);
builder.addAssetProfileUpdateMsg(assetProfileMsgConstructor.constructAssetProfileUpdatedMsg(msgType, assetProfile));
}
downlinkMsg = builder.build();
@@ -72,8 +145,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..aceab6692c 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,27 +15,88 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.asset;
+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.EdgeUtils;
import org.thingsboard.server.common.data.asset.AssetProfile;
+import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AssetProfileId;
+import org.thingsboard.server.common.data.id.DashboardId;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
+import org.thingsboard.server.gen.edge.v1.EdgeVersion;
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;
+
+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 [{}]", tenantId, assetProfileUpdateMsg, e);
+ return Futures.immediateFailedFuture(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
- public DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent) {
+ private void saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg, Edge edge) {
+ Pair resultPair = super.saveOrUpdateAssetProfile(tenantId, assetProfileId, assetProfileUpdateMsg);
+ Boolean created = resultPair.getFirst();
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), assetProfileId);
+ pushAssetProfileCreatedEventToRuleEngine(tenantId, edge, assetProfileId);
+ }
+ Boolean assetProfileNameUpdated = resultPair.getSecond();
+ if (assetProfileNameUpdated) {
+ saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET_PROFILE, EdgeEventActionType.UPDATED, assetProfileId, null);
+ }
+ }
+
+ private void pushAssetProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, AssetProfileId assetProfileId) {
+ try {
+ AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId);
+ String assetProfileAsString = JacksonUtil.toString(assetProfile);
+ TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null);
+ pushEntityEventToRuleEngine(tenantId, assetProfileId, null, TbMsgType.ENTITY_CREATED, assetProfileAsString, msgMetaData);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to push asset profile action to rule engine: {}", tenantId, assetProfileId, TbMsgType.ENTITY_CREATED.name(), e);
+ }
+ }
+
+ public DownlinkMsg convertAssetProfileEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
AssetProfileId assetProfileId = new AssetProfileId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
@@ -44,6 +105,7 @@ public class AssetProfileEdgeProcessor extends BaseEdgeProcessor {
AssetProfile assetProfile = assetProfileService.findAssetProfileById(edgeEvent.getTenantId(), assetProfileId);
if (assetProfile != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
+ assetProfile = checkIfAssetProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, assetProfile, edgeVersion);
AssetProfileUpdateMsg assetProfileUpdateMsg =
assetProfileMsgConstructor.constructAssetProfileUpdatedMsg(msgType, assetProfile);
downlinkMsg = DownlinkMsg.newBuilder()
@@ -64,8 +126,20 @@ public class AssetProfileEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public ListenableFuture processAssetProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
+ @Override
+ protected void setDefaultRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) {
+ // do nothing on cloud
}
+ @Override
+ protected void setDefaultEdgeRuleChainId(TenantId tenantId,AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) {
+ UUID defaultEdgeRuleChainUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultRuleChainIdMSB(), assetProfileUpdateMsg.getDefaultRuleChainIdLSB());
+ assetProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainUUID != null ? new RuleChainId(defaultEdgeRuleChainUUID) : null);
+ }
+
+ @Override
+ protected void setDefaultDashboardId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg) {
+ UUID defaultDashboardUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultDashboardIdMSB(), assetProfileUpdateMsg.getDefaultDashboardIdLSB());
+ assetProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null);
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java
new file mode 100644
index 0000000000..f8dcdbd8f6
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProcessor.java
@@ -0,0 +1,80 @@
+/**
+ * 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 {}",
+ tenantId, 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);
+ } catch (Exception e) {
+ log.error("[{}] Failed to process asset update msg [{}]", tenantId, assetUpdateMsg, e);
+ throw e;
+ } 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..67c8f8de44
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/BaseAssetProfileProcessor.java
@@ -0,0 +1,83 @@
+/**
+ * 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.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.asset.AssetProfile;
+import org.thingsboard.server.common.data.id.AssetProfileId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg;
+import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+public abstract class BaseAssetProfileProcessor extends BaseEdgeProcessor {
+
+ protected Pair saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) {
+ boolean created = false;
+ boolean assetProfileNameUpdated = 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 assetProfileByName = assetProfileService.findAssetProfileByName(tenantId, assetProfileName);
+ if (assetProfileByName != null && !assetProfileByName.getId().equals(assetProfileId)) {
+ assetProfileName = assetProfileName + "_" + StringUtils.randomAlphabetic(15);
+ log.warn("[{}] Asset profile with name {} already exists. Renaming asset profile name to {}",
+ tenantId, assetProfileUpdateMsg.getName(), assetProfileName);
+ assetProfileNameUpdated = true;
+ }
+ 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);
+
+ setDefaultRuleChainId(tenantId, assetProfile, assetProfileUpdateMsg);
+ setDefaultEdgeRuleChainId(tenantId, assetProfile, assetProfileUpdateMsg);
+ setDefaultDashboardId(tenantId, assetProfile, assetProfileUpdateMsg);
+
+ assetProfileValidator.validate(assetProfile, AssetProfile::getTenantId);
+ if (created) {
+ assetProfile.setId(assetProfileId);
+ }
+ assetProfileService.saveAssetProfile(assetProfile, false);
+ } catch (Exception e) {
+ log.error("[{}] Failed to process asset profile update msg [{}]", tenantId, assetProfileUpdateMsg, e);
+ throw e;
+ } finally {
+ assetCreationLock.unlock();
+ }
+ return Pair.of(created, assetProfileNameUpdated);
+ }
+
+ protected abstract void setDefaultRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg);
+
+ protected abstract void setDefaultEdgeRuleChainId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg);
+
+ protected abstract void setDefaultDashboardId(TenantId tenantId, AssetProfile assetProfile, AssetProfileUpdateMsg assetProfileUpdateMsg);
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java
new file mode 100644
index 0000000000..687e14a07d
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java
@@ -0,0 +1,84 @@
+/**
+ * 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.setImage(dashboardUpdateMsg.hasImage() ? dashboardUpdateMsg.getImage() : null);
+ dashboard.setConfiguration(JacksonUtil.toJsonNode(dashboardUpdateMsg.getConfiguration()));
+
+ Set assignedCustomers = null;
+ if (dashboardUpdateMsg.hasAssignedCustomers()) {
+ assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() {});
+ assignedCustomers = filterNonExistingCustomers(tenantId, assignedCustomers);
+ dashboard.setAssignedCustomers(assignedCustomers);
+ }
+
+ dashboard.setMobileOrder(dashboardUpdateMsg.hasMobileOrder() ? dashboardUpdateMsg.getMobileOrder() : null);
+ dashboard.setMobileHide(dashboardUpdateMsg.getMobileHide());
+
+ 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;
+ }
+
+ protected abstract Set filterNonExistingCustomers(TenantId tenantId, Set assignedCustomers);
+
+ 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..fc19d81789 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java
@@ -15,25 +15,88 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.dashboard;
+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.EdgeUtils;
+import org.thingsboard.server.common.data.ShortCustomerInfo;
+import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.id.CustomerId;
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.TbMsgMetaData;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
+
+import java.util.Set;
+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);
+ String dashboardAsString = JacksonUtil.toString(dashboard);
+ TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null);
+ pushEntityEventToRuleEngine(tenantId, dashboardId, null, TbMsgType.ENTITY_CREATED, dashboardAsString, msgMetaData);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to push dashboard action to rule engine: {}", tenantId, dashboardId, TbMsgType.ENTITY_CREATED.name(), e);
+ }
+ }
public DownlinkMsg convertDashboardEventToDownlink(EdgeEvent edgeEvent) {
DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId());
@@ -68,7 +131,9 @@ public class DashboardEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public ListenableFuture processDashboardNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotification(tenantId, edgeNotificationMsg);
+ @Override
+ protected Set filterNonExistingCustomers(TenantId tenantId, Set assignedCustomers) {
+ // do nothing on cloud
+ return assignedCustomers;
}
}
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..7993eb4fd8 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java
@@ -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 {}",
+ tenantId, deviceUpdateMsg.getName(), deviceName);
+ deviceNameUpdated = true;
}
device.setName(deviceName);
device.setType(deviceUpdateMsg.getType());
@@ -97,8 +97,11 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
deviceCredentials.setCredentialsId(StringUtils.randomAlphanumeric(20));
deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
}
- tbClusterService.onDeviceUpdated(savedDevice, created ? null : device, false);
- } finally {
+ tbClusterService.onDeviceUpdated(savedDevice, created ? null : device);
+ } catch (Exception e) {
+ log.error("[{}] Failed to process device update msg [{}]", tenantId, deviceUpdateMsg, e);
+ throw e;
+ } finally {
deviceCreationLock.unlock();
}
return Pair.of(created, deviceNameUpdated);
@@ -110,9 +113,11 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
return dbCallbackExecutorService.submit(() -> {
Device device = deviceService.findDeviceById(tenantId, deviceId);
if (device != null) {
- log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
- device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue());
+ log.debug("[{}] Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
+ tenantId, device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue());
try {
+ edgeSynchronizationManager.getSync().set(true);
+
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType()));
deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId());
@@ -120,12 +125,14 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor {
? deviceCredentialsUpdateMsg.getCredentialsValue() : null);
deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials);
} catch (Exception e) {
- log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]",
- device.getName(), deviceCredentialsUpdateMsg, e);
+ log.error("[{}] Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]",
+ tenantId, device.getName(), deviceCredentialsUpdateMsg, e);
throw new RuntimeException(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
} else {
- log.warn("Can't find device by id [{}], deviceCredentialsUpdateMsg [{}]", deviceId, deviceCredentialsUpdateMsg);
+ log.warn("[{}] Can't find device by id [{}], deviceCredentialsUpdateMsg [{}]", tenantId, deviceId, deviceCredentialsUpdateMsg);
}
return null;
});
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java
new file mode 100644
index 0000000000..bd35a42e59
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.rpc.processor.device;
+
+import com.datastax.oss.driver.api.core.uuid.Uuids;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.util.Pair;
+import org.thingsboard.server.common.data.DeviceProfile;
+import org.thingsboard.server.common.data.DeviceProfileProvisionType;
+import org.thingsboard.server.common.data.DeviceProfileType;
+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.DeviceProfileId;
+import org.thingsboard.server.common.data.id.OtaPackageId;
+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 abstract class BaseDeviceProfileProcessor extends BaseEdgeProcessor {
+
+ @Autowired
+ private DataDecodingEncodingService dataDecodingEncodingService;
+
+ protected Pair saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
+ boolean created = false;
+ boolean deviceProfileNameUpdated = false;
+ deviceCreationLock.lock();
+ try {
+ DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
+ String deviceProfileName = deviceProfileUpdateMsg.getName();
+ if (deviceProfile == null) {
+ created = true;
+ deviceProfile = new DeviceProfile();
+ deviceProfile.setTenantId(tenantId);
+ deviceProfile.setCreatedTime(Uuids.unixTimestamp(deviceProfileId.getId()));
+ }
+ DeviceProfile deviceProfileByName = deviceProfileService.findDeviceProfileByName(tenantId, deviceProfileName);
+ if (deviceProfileByName != null && !deviceProfileByName.getId().equals(deviceProfileId)) {
+ deviceProfileName = deviceProfileName + "_" + StringUtils.randomAlphabetic(15);
+ log.warn("[{}] Device profile with name {} already exists. Renaming device profile name to {}",
+ tenantId, deviceProfileUpdateMsg.getName(), deviceProfileName);
+ deviceProfileNameUpdated = true;
+ }
+ deviceProfile.setName(deviceProfileName);
+ deviceProfile.setDescription(deviceProfileUpdateMsg.hasDescription() ? deviceProfileUpdateMsg.getDescription() : null);
+ deviceProfile.setType(DeviceProfileType.valueOf(deviceProfileUpdateMsg.getType()));
+ deviceProfile.setTransportType(deviceProfileUpdateMsg.hasTransportType()
+ ? 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));
+
+ setDefaultRuleChainId(tenantId, deviceProfile, deviceProfileUpdateMsg);
+ setDefaultEdgeRuleChainId(tenantId, deviceProfile, deviceProfileUpdateMsg);
+ setDefaultDashboardId(tenantId, deviceProfile, deviceProfileUpdateMsg);
+
+ 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);
+ } catch (Exception e) {
+ log.error("[{}] Failed to process device profile update msg [{}]", tenantId, deviceProfileUpdateMsg, e);
+ throw e;
+ } finally {
+ deviceCreationLock.unlock();
+ }
+ return Pair.of(created, deviceProfileNameUpdated);
+ }
+
+ protected abstract void setDefaultRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg);
+
+ protected abstract void setDefaultEdgeRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg);
+
+ protected abstract void setDefaultDashboardId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg);
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java
index 3e617de8c6..7b1da9a297 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
@@ -36,25 +36,22 @@ 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;
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.EdgeVersion;
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 +68,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 +92,8 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
} else {
return Futures.immediateFailedFuture(e);
}
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
}
}
@@ -111,50 +112,15 @@ 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(),
- getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
- tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
- @Override
- public void onSuccess(TbQueueMsgMetadata metadata) {
- log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", device);
- }
-
- @Override
- public void onFailure(Throwable t) {
- log.debug("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());
+ String deviceAsString = JacksonUtil.toString(device);
+ TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, device.getCustomerId());
+ pushEntityEventToRuleEngine(tenantId, deviceId, device.getCustomerId(), TbMsgType.ENTITY_CREATED, deviceAsString, msgMetaData);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to push device action to rule engine: {}", tenantId, deviceId, TbMsgType.ENTITY_CREATED.name(), e);
}
- 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) {
@@ -186,7 +152,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
@Override
public void onFailure(Throwable t) {
- log.error("Can't process push notification to core [{}]", deviceRpcCallMsg, t);
+ log.error("[{}] Can't process push notification to core [{}]", tenantId, deviceRpcCallMsg, t);
futureToSet.setException(t);
}
};
@@ -216,29 +182,29 @@ 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
public void onSuccess(TbQueueMsgMetadata metadata) {
- log.debug("Successfully send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}",
- device, deviceRpcCallMsg);
+ log.debug("[{}] Successfully send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}",
+ tenantId, device, deviceRpcCallMsg);
}
@Override
public void onFailure(Throwable t) {
- log.debug("Failed to send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}",
- device, deviceRpcCallMsg, t);
+ log.debug("[{}] Failed to send TO_SERVER_RPC_REQUEST to rule engine [{}], deviceRpcCallMsg {}",
+ tenantId, device, deviceRpcCallMsg, t);
}
});
} catch (JsonProcessingException | IllegalArgumentException e) {
- log.warn("[{}] Failed to push TO_SERVER_RPC_REQUEST to rule engine. deviceRpcCallMsg {}", deviceId, deviceRpcCallMsg, e);
+ log.warn("[{}][{}] Failed to push TO_SERVER_RPC_REQUEST to rule engine. deviceRpcCallMsg {}", tenantId, deviceId, deviceRpcCallMsg, e);
}
return Futures.immediateFuture(null);
}
- public DownlinkMsg convertDeviceEventToDownlink(EdgeEvent edgeEvent) {
+ public DownlinkMsg convertDeviceEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
@@ -257,6 +223,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor {
.addDeviceUpdateMsg(deviceUpdateMsg);
if (UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(edgeEvent.getTenantId(), device.getDeviceProfileId());
+ deviceProfile = checkIfDeviceProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, deviceProfile, edgeVersion);
builder.addDeviceProfileUpdateMsg(deviceProfileMsgConstructor.constructDeviceProfileUpdatedMsg(msgType, deviceProfile));
}
downlinkMsg = builder.build();
@@ -308,8 +275,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..d482f42cf6 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,27 +15,88 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.device;
+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.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
+import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
+import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.msg.TbMsgType;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
+import org.thingsboard.server.gen.edge.v1.EdgeVersion;
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;
+
+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 [{}]", tenantId, deviceProfileUpdateMsg, e);
+ return Futures.immediateFailedFuture(e);
+ } finally {
+ edgeSynchronizationManager.getSync().remove();
+ }
+ }
+
+ private void saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg, Edge edge) {
+ Pair resultPair = super.saveOrUpdateDeviceProfile(tenantId, deviceProfileId, deviceProfileUpdateMsg);
+ Boolean created = resultPair.getFirst();
+ if (created) {
+ createRelationFromEdge(tenantId, edge.getId(), deviceProfileId);
+ pushDeviceProfileCreatedEventToRuleEngine(tenantId, edge, deviceProfileId);
+ }
+ Boolean deviceProfileNameUpdated = resultPair.getSecond();
+ if (deviceProfileNameUpdated) {
+ saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE, EdgeEventActionType.UPDATED, deviceProfileId, null);
+ }
+ }
+
+ private void pushDeviceProfileCreatedEventToRuleEngine(TenantId tenantId, Edge edge, DeviceProfileId deviceProfileId) {
+ try {
+ DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
+ String deviceProfileAsString = JacksonUtil.toString(deviceProfile);
+ TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, null);
+ pushEntityEventToRuleEngine(tenantId, deviceProfileId, null, TbMsgType.ENTITY_CREATED, deviceProfileAsString, msgMetaData);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to push device profile action to rule engine: {}", tenantId, deviceProfileId, TbMsgType.ENTITY_CREATED.name(), e);
+ }
+ }
- public DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent) {
+ public DownlinkMsg convertDeviceProfileEventToDownlink(EdgeEvent edgeEvent, EdgeId edgeId, EdgeVersion edgeVersion) {
DeviceProfileId deviceProfileId = new DeviceProfileId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (edgeEvent.getAction()) {
@@ -44,6 +105,7 @@ public class DeviceProfileEdgeProcessor extends BaseEdgeProcessor {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(edgeEvent.getTenantId(), deviceProfileId);
if (deviceProfile != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
+ deviceProfile = checkIfDeviceProfileDefaultFieldsAssignedToEdge(edgeEvent.getTenantId(), edgeId, deviceProfile, edgeVersion);
DeviceProfileUpdateMsg deviceProfileUpdateMsg =
deviceProfileMsgConstructor.constructDeviceProfileUpdatedMsg(msgType, deviceProfile);
downlinkMsg = DownlinkMsg.newBuilder()
@@ -64,7 +126,20 @@ public class DeviceProfileEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public ListenableFuture processDeviceProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
- return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
+ @Override
+ protected void setDefaultRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
+ // do nothing on cloud
+ }
+
+ @Override
+ protected void setDefaultEdgeRuleChainId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
+ UUID defaultEdgeRuleChainUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultRuleChainIdMSB(), deviceProfileUpdateMsg.getDefaultRuleChainIdLSB());
+ deviceProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainUUID != null ? new RuleChainId(defaultEdgeRuleChainUUID) : null);
+ }
+
+ @Override
+ protected void setDefaultDashboardId(TenantId tenantId, DeviceProfile deviceProfile, DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
+ UUID defaultDashboardUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultDashboardIdMSB(), deviceProfileUpdateMsg.getDefaultDashboardIdLSB());
+ deviceProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java
index 123209afc1..b38659c881 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/edge/EdgeProcessor.java
@@ -85,7 +85,7 @@ public class EdgeProcessor extends BaseEdgeProcessor {
do {
pageData = userService.findCustomerUsers(tenantId, customerId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
- log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size());
+ log.trace("[{}][{}][{}] user(s) are going to be added to edge.", tenantId, edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) {
futures.add(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null));
}
@@ -108,7 +108,7 @@ public class EdgeProcessor extends BaseEdgeProcessor {
return Futures.immediateFuture(null);
}
} catch (Exception e) {
- log.error("Exception during processing edge event", e);
+ log.error("[{}] Exception during processing edge event", tenantId, e);
return Futures.immediateFailedFuture(e);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/BaseEntityViewProcessor.java
new file mode 100644
index 0000000000..cca0057707
--- /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 {}",
+ tenantId, 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..01dd414aee 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java
@@ -15,25 +15,94 @@
*/
package org.thingsboard.server.service.edge.rpc.processor.entityview;
+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.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.TbMsgMetaData;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
-import org.thingsboard.server.gen.transport.TransportProtos;
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);
+ pushEntityViewCreatedEventToRuleEngine(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 pushEntityViewCreatedEventToRuleEngine(TenantId tenantId, Edge edge, EntityViewId entityViewId) {
+ try {
+ EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId);
+ String entityViewAsString = JacksonUtil.toString(entityView);
+ TbMsgMetaData msgMetaData = getEdgeActionTbMsgMetaData(edge, entityView.getCustomerId());
+ pushEntityEventToRuleEngine(tenantId, entityViewId, entityView.getCustomerId(), TbMsgType.ENTITY_CREATED, entityViewAsString, msgMetaData);
+ } catch (Exception e) {
+ log.warn("[{}][{}] Failed to push entity view action to rule engine: {}", tenantId, entityViewId, TbMsgType.ENTITY_CREATED.name(), e);
+ }
+ }
public DownlinkMsg convertEntityViewEventToDownlink(EdgeEvent edgeEvent) {
EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId());
@@ -67,8 +136,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..f7be0cf1f4 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java
@@ -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);
+ log.warn("[{}] Skipping relating update msg because from/to entity doesn't exists on edge, {}", tenantId, relationUpdateMsg);
+ 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 c3bd338ffc..2f4c3ff2d0 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.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.dao.model.ModelConstants;
@@ -130,7 +130,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
result.add(processAttributeDeleteMsg(tenantId, entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType()));
}
} else {
- log.warn("Skipping telemetry update msg because entity doesn't exists on edge, {}", entityData);
+ log.warn("[{}] Skipping telemetry update msg because entity doesn't exists on edge, {}", tenantId, entityData);
}
return result;
}
@@ -172,7 +172,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
}
break;
default:
- log.debug("Using empty metadata for entityId [{}]", entityId);
+ log.debug("[{}] Using empty metadata for entityId [{}]", tenantId, entityId);
break;
}
return new ImmutablePair<>(metaData, customerId != null ? customerId : new CustomerId(ModelConstants.NULL_UUID));
@@ -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) {
@@ -193,7 +193,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onFailure(Throwable t) {
- log.error("Can't process post telemetry [{}]", msg, t);
+ log.error("[{}] Can't process post telemetry [{}]", tenantId, msg, t);
futureToSet.setException(t);
}
});
@@ -207,7 +207,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
if (EntityType.DEVICE.equals(entityId.getEntityType())) {
DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
if (deviceProfile == null) {
- log.warn("[{}] Device profile is null!", entityId);
+ log.warn("[{}][{}] Device profile is null!", tenantId, entityId);
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
queueName = deviceProfile.getDefaultQueueName();
@@ -215,7 +215,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
} else if (EntityType.ASSET.equals(entityId.getEntityType())) {
AssetProfile assetProfile = assetProfileCache.get(tenantId, new AssetId(entityId.getId()));
if (assetProfile == null) {
- log.warn("[{}] Asset profile is null!", entityId);
+ log.warn("[{}][{}] Asset profile is null!", tenantId, entityId);
} else {
ruleChainId = assetProfile.getDefaultRuleChainId();
queueName = assetProfile.getDefaultQueueName();
@@ -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) {
@@ -237,7 +237,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onFailure(Throwable t) {
- log.error("Can't process post attributes [{}]", msg, t);
+ log.error("[{}] Can't process post attributes [{}]", tenantId, msg, t);
futureToSet.setException(t);
}
});
@@ -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
@@ -267,7 +267,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onFailure(Throwable t) {
- log.error("Can't process attributes update [{}]", msg, t);
+ log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t);
futureToSet.setException(t);
}
});
@@ -275,7 +275,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onFailure(Throwable t) {
- log.error("Can't process attributes update [{}]", msg, t);
+ log.error("[{}] Can't process attributes update [{}]", tenantId, msg, t);
futureToSet.setException(t);
}
});
@@ -300,7 +300,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
@Override
public void onFailure(Throwable t) {
- log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t);
+ log.error("[{}] Can't process attribute delete msg [{}]", tenantId, attributeDeleteMsg, t);
futureToSet.setException(t);
}
});
@@ -311,7 +311,8 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
}, dbCallbackExecutorService);
}
- public EntityDataProto convertTelemetryEventToEntityDataProto(EntityType entityType,
+ public EntityDataProto convertTelemetryEventToEntityDataProto(TenantId tenantId,
+ EntityType entityType,
UUID entityUUID,
EdgeEventActionType actionType,
JsonNode body) throws JsonProcessingException {
@@ -342,11 +343,11 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
entityId = new EdgeId(entityUUID);
break;
default:
- log.warn("Unsupported edge event type [{}]", entityType);
+ log.warn("[{}] Unsupported edge event type [{}]", tenantId, entityType);
return null;
}
JsonElement entityData = JsonParser.parseString(JacksonUtil.OBJECT_MAPPER.writeValueAsString(body));
- return entityDataMsgConstructor.constructEntityDataMsg(entityId, actionType, entityData);
+ return entityDataMsgConstructor.constructEntityDataMsg(tenantId, entityId, actionType, entityData);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java
index 66c5596545..861d766638 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java
@@ -38,7 +38,8 @@ public class TelemetryEdgeProcessor extends BaseTelemetryProcessor {
public DownlinkMsg convertTelemetryEventToDownlink(EdgeEvent edgeEvent) throws JsonProcessingException {
EntityType entityType = EntityType.valueOf(edgeEvent.getType().name());
- EntityDataProto entityDataProto = convertTelemetryEventToEntityDataProto(entityType, edgeEvent.getEntityId(),
+ EntityDataProto entityDataProto = convertTelemetryEventToEntityDataProto(
+ edgeEvent.getTenantId(), entityType, edgeEvent.getEntityId(),
edgeEvent.getAction(), edgeEvent.getBody());
return DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/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..877ece1b15 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,21 +15,20 @@
*/
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;
+import java.util.List;
+
@Component
@Slf4j
@TbCoreComponent
@@ -43,9 +42,10 @@ public class WidgetBundleEdgeProcessor extends BaseEdgeProcessor {
case UPDATED:
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(edgeEvent.getTenantId(), widgetsBundleId);
if (widgetsBundle != null) {
+ List widgets = widgetTypeService.findWidgetFqnsByWidgetsBundleId(edgeEvent.getTenantId(), widgetsBundleId);
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
WidgetsBundleUpdateMsg widgetsBundleUpdateMsg =
- widgetsBundleMsgConstructor.constructWidgetsBundleUpdateMsg(msgType, widgetsBundle);
+ widgetsBundleMsgConstructor.constructWidgetsBundleUpdateMsg(msgType, widgetsBundle, widgets);
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addWidgetsBundleUpdateMsg(widgetsBundleUpdateMsg)
@@ -63,8 +63,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..46bb940da9 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());
}
@@ -175,7 +177,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
entityData.put("kv", attributes);
entityData.put("scope", scope);
JsonNode body = JacksonUtil.OBJECT_MAPPER.valueToTree(entityData);
- log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body);
+ log.debug("[{}] Sending attributes data msg, entityId [{}], attributes [{}]", tenantId, entityId, body);
future = saveEdgeEvent(tenantId, edge.getId(), entityType, EdgeEventActionType.ATTRIBUTES_UPDATED, entityId, body);
} else {
future = Futures.immediateFuture(null);
@@ -183,7 +185,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
}
return Futures.transformAsync(future, v -> processLatestTimeseriesAndAddToEdgeQueue(tenantId, entityId, edge, entityType), dbCallbackExecutorService);
} catch (Exception e) {
- String errMsg = String.format("[%s] Failed to save attribute updates to the edge [%s]", edge.getId(), attributesRequestMsg);
+ String errMsg = String.format("[%s][%s] Failed to save attribute updates to the edge [%s]", tenantId, edge.getId(), attributesRequestMsg);
log.error(errMsg, e);
return Futures.immediateFailedFuture(new RuntimeException(errMsg, e));
}
@@ -237,7 +239,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
if (relationsList != null && !relationsList.isEmpty()) {
List> futures = new ArrayList<>();
for (List entityRelations : relationsList) {
- log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size());
+ log.trace("[{}][{}][{}][{}] relation(s) are going to be pushed to edge.", tenantId, edge.getId(), entityId, entityRelations.size());
for (EntityRelation relation : entityRelations) {
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
@@ -250,7 +252,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
JacksonUtil.OBJECT_MAPPER.valueToTree(relation)));
}
} catch (Exception e) {
- String errMsg = String.format("[%s] Exception during loading relation [%s] to edge on sync!", edge.getId(), relation);
+ String errMsg = String.format("[%s][%s] Exception during loading relation [%s] to edge on sync!", tenantId, edge.getId(), relation);
log.error(errMsg, e);
futureToSet.setException(new RuntimeException(errMsg, e));
return;
@@ -265,7 +267,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override
public void onFailure(Throwable throwable) {
- String errMsg = String.format("[%s] Exception during saving edge events [%s]!", edge.getId(), relationRequestMsg);
+ String errMsg = String.format("[%s][%s] Exception during saving edge events [%s]!", tenantId, edge.getId(), relationRequestMsg);
log.error(errMsg, throwable);
futureToSet.setException(new RuntimeException(errMsg, throwable));
}
@@ -274,7 +276,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
futureToSet.set(null);
}
} catch (Exception e) {
- log.error("Exception during loading relation(s) to edge on sync!", e);
+ log.error("[{}] Exception during loading relation(s) to edge on sync!", tenantId, e);
futureToSet.setException(e);
}
}
@@ -328,7 +330,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
WidgetsBundle widgetsBundleById = widgetsBundleService.findWidgetsBundleById(tenantId, widgetsBundleId);
if (widgetsBundleById != null) {
List widgetTypesToPush =
- widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundleById.getTenantId(), widgetsBundleById.getAlias());
+ widgetTypeService.findWidgetTypesByWidgetsBundleId(widgetsBundleById.getTenantId(), widgetsBundleId);
for (WidgetType widgetType : widgetTypesToPush) {
futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null));
}
@@ -372,7 +374,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override
public void onFailure(Throwable t) {
- log.error("Exception during loading relation to edge on sync!", t);
+ log.error("[{}] Exception during loading relation to edge on sync!", tenantId, t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
diff --git a/application/src/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..bd09b04a02 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.service.entitiy.alarm;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,11 +34,15 @@ 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.AlarmId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.common.data.page.SortOrder;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import java.util.ArrayList;
import java.util.List;
@Service
@@ -62,10 +67,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
if (!result.isSuccessful()) {
throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND);
}
- actionType = result.isCreated() ? ActionType.ADDED : ActionType.UPDATED;
- if (result.isModified()) {
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), actionType, user);
- }
AlarmInfo resultAlarm = result.getAlarm();
if (alarm.isAcknowledged() && !resultAlarm.isAcknowledged()) {
resultAlarm = ack(resultAlarm, alarm.getAckTs(), user);
@@ -80,6 +81,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
} else if (newAssignee == null && curAssignee != null) {
resultAlarm = unassign(alarm, alarm.getAssignTs(), user);
}
+ if (result.isModified()) {
+ notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), resultAlarm,
+ resultAlarm.getCustomerId(), actionType, user);
+ }
return new Alarm(resultAlarm);
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM), alarm, actionType, user, e);
@@ -98,25 +103,16 @@ 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())
- .type(AlarmCommentType.SYSTEM)
- .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was acknowledged by user %s",
- (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))
- .put("userId", user.getId().toString())
- .put("subtype", "ACK"))
- .build();
- try {
- alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
- } catch (ThingsboardException e) {
- log.error("Failed to save alarm comment", e);
- }
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_ACK, user);
+ String systemComment = String.format("Alarm was acknowledged by user %s", user.getTitle());
+ addSystemAlarmComment(alarmInfo, user, "ACK", systemComment);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_ACK, user);
} else {
throw new ThingsboardException("Alarm was already acknowledged!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
- return result.getAlarm();
+ return alarmInfo;
}
@Override
@@ -130,25 +126,16 @@ 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())
- .type(AlarmCommentType.SYSTEM)
- .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was cleared by user %s",
- (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))
- .put("userId", user.getId().toString())
- .put("subtype", "CLEAR"))
- .build();
- try {
- alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
- } catch (ThingsboardException e) {
- log.error("Failed to save alarm comment", e);
- }
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_CLEAR, user);
+ String systemComment = String.format("Alarm was cleared by user %s", user.getTitle());
+ addSystemAlarmComment(alarmInfo, user, "CLEAR", systemComment);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_CLEAR, user);
} else {
throw new ThingsboardException("Alarm was already cleared!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
- return result.getAlarm();
+ return alarmInfo;
}
@Override
@@ -160,22 +147,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
AlarmInfo alarmInfo = result.getAlarm();
if (result.isModified()) {
AlarmAssignee assignee = alarmInfo.getAssignee();
- AlarmComment alarmComment = AlarmComment.builder()
- .alarmId(alarm.getId())
- .type(AlarmCommentType.SYSTEM)
- .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was assigned by user %s to user %s",
- (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName(),
- (assignee.getFirstName() == null || assignee.getLastName() == null) ? assignee.getEmail() : assignee.getFirstName() + " " + assignee.getLastName()))
- .put("userId", user.getId().toString())
- .put("assigneeId", assignee.getId().toString())
- .put("subtype", "ASSIGN"))
- .build();
- try {
- alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
- } catch (ThingsboardException e) {
- log.error("Failed to save alarm comment", e);
- }
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_ASSIGNED, user);
+ String systemComment = String.format("Alarm was assigned by user %s to user %s", user.getTitle(), assignee.getTitle());
+ addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment, assignee.getId());
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_ASSIGNED, user);
} else {
throw new ThingsboardException("Alarm was already assigned to this user!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
@@ -190,36 +165,84 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
}
AlarmInfo alarmInfo = result.getAlarm();
if (result.isModified()) {
- AlarmComment alarmComment = AlarmComment.builder()
- .alarmId(alarm.getId())
- .type(AlarmCommentType.SYSTEM)
- .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned by user %s",
- (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))
- .put("userId", user.getId().toString())
- .put("subtype", "ASSIGN"))
- .build();
- try {
- alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
- } catch (ThingsboardException e) {
- log.error("Failed to save alarm comment", e);
- }
- notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user);
+ String systemComment = String.format("Alarm was unassigned by user %s", user.getTitle());
+ addSystemAlarmComment(alarmInfo, user, "ASSIGN", systemComment);
+ notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo,
+ alarmInfo.getCustomerId(), ActionType.ALARM_UNASSIGNED, user);
} else {
throw new ThingsboardException("Alarm was already unassigned!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
return alarmInfo;
}
+ @Override
+ public List unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs) {
+ List totalAlarmIds = new ArrayList<>();
+ PageLink pageLink = new PageLink(100, 0, null, new SortOrder("id", SortOrder.Direction.ASC));
+ while (true) {
+ PageData pageData = alarmService.findAlarmIdsByAssigneeId(user.getTenantId(), user.getId(), pageLink);
+ List alarmIds = pageData.getData();
+ if (alarmIds.isEmpty()) {
+ break;
+ }
+ processAlarmsUnassignment(tenantId, user, alarmIds, unassignTs);
+ totalAlarmIds.addAll(alarmIds);
+ pageLink = pageLink.nextPageLink();
+ }
+ return totalAlarmIds;
+ }
+
@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());
}
private static long getOrDefault(long ts) {
return ts > 0 ? ts : System.currentTimeMillis();
}
+
+ private void processAlarmsUnassignment(TenantId tenantId, User user, List alarmIds, long unassignTs) {
+ for (AlarmId alarmId : alarmIds) {
+ log.trace("[{}] Unassigning alarm {} userId {}", tenantId, alarmId, user.getId());
+ AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(user.getTenantId(), alarmId, unassignTs);
+ if (!result.isSuccessful()) {
+ log.error("[{}] Cannot unassign alarm {} userId {}", tenantId, alarmId, user.getId());
+ continue;
+ }
+ if (result.isModified()) {
+ String comment = String.format("Alarm was unassigned because user %s - was deleted", user.getTitle());
+ addSystemAlarmComment(result.getAlarm(), null, "ASSIGN", comment);
+ notificationEntityService.logEntityAction(result.getAlarm().getTenantId(), result.getAlarm().getOriginator(), result.getAlarm(), result.getAlarm().getCustomerId(), ActionType.ALARM_UNASSIGNED, null);
+ }
+ }
+ }
+
+ private void addSystemAlarmComment(Alarm alarm, User user, String subType, String commentText) {
+ addSystemAlarmComment(alarm, user, subType, commentText, null);
+ }
+
+ private void addSystemAlarmComment(Alarm alarm, User user, String subType, String commentText, UserId assigneeId) {
+ ObjectNode commentNode = JacksonUtil.newObjectNode();
+ commentNode.put("text", commentText)
+ .put("subtype", subType);
+ if (user != null) {
+ commentNode.put("userId", user.getId().getId().toString());
+ }
+ if (assigneeId != null) {
+ commentNode.put("assigneeId", assigneeId.getId().toString());
+ }
+ AlarmComment alarmComment = AlarmComment.builder()
+ .alarmId(alarm.getId())
+ .type(AlarmCommentType.SYSTEM)
+ .comment(commentNode)
+ .build();
+ try {
+ alarmCommentService.saveAlarmComment(alarm, alarmComment, user);
+ } catch (ThingsboardException e) {
+ log.error("Failed to save alarm comment", e);
+ }
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
index a2ae9c8cc7..24af55f38b 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
@@ -19,8 +19,12 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.AlarmId;
+import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
+import java.util.List;
+
public interface TbAlarmService {
Alarm save(Alarm entity, User user) throws ThingsboardException;
@@ -37,5 +41,7 @@ public interface TbAlarmService {
AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException;
+ List unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs);
+
Boolean delete(Alarm alarm, User user);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/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 e59340b99b..d511d6d4e4 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 181e0b8b80..ca953006b4 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
@@ -52,7 +52,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);
@@ -62,12 +62,11 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
try {
mailService.sendActivationEmail(activateUrl, email);
} catch (ThingsboardException e) {
- userService.deleteUser(tenantId, savedUser.getId());
+ userService.deleteUser(tenantId, savedUser);
throw e;
}
}
- 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);
@@ -76,16 +75,16 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
}
@Override
- public void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException {
- UserId userId = tbUser.getId();
+ public void delete(TenantId tenantId, CustomerId customerId, User user, User responsibleUser) throws ThingsboardException {
+ ActionType actionType = ActionType.DELETED;
+ UserId userId = user.getId();
try {
- userService.deleteUser(tenantId, userId);
- notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser,
- user, ActionType.DELETED, true, null, customerId.toString());
+ userService.deleteUser(tenantId, user);
+ notificationEntityService.logEntityAction(tenantId, userId, user, customerId, actionType, responsibleUser, customerId.toString());
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER),
- ActionType.DELETED, user, e, userId.toString());
+ actionType, responsibleUser, e, userId.toString());
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java
index b5a5b83bfd..2c8faa1bdf 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java
@@ -25,5 +25,5 @@ import jakarta.servlet.http.HttpServletRequest;
public interface TbUserService {
User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail, HttpServletRequest request, User user) throws ThingsboardException;
- void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException;
+ void delete(TenantId tenantId, CustomerId customerId, User user, User responsibleUser) throws ThingsboardException;
}
diff --git a/application/src/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..ffa11e8c46 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
@@ -21,17 +21,23 @@ 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.TenantId;
+import org.thingsboard.server.common.data.id.WidgetTypeId;
+import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
+import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import java.util.List;
+
@Service
@TbCoreComponent
@AllArgsConstructor
public class DefaultWidgetsBundleService extends AbstractTbEntityService implements TbWidgetsBundleService {
private final WidgetsBundleService widgetsBundleService;
+ private final WidgetTypeService widgetTypeService;
@Override
public WidgetsBundle save(WidgetsBundle widgetsBundle, User user) throws Exception {
@@ -40,8 +46,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,15 +57,26 @@ 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;
}
}
+
+ @Override
+ public void updateWidgetsBundleWidgetTypes(WidgetsBundleId widgetsBundleId, List widgetTypeIds, User user) throws Exception {
+ widgetTypeService.updateWidgetsBundleWidgetTypes(user.getTenantId(), widgetsBundleId, widgetTypeIds);
+ autoCommit(user, widgetsBundleId);
+ }
+
+ @Override
+ public void updateWidgetsBundleWidgetFqns(WidgetsBundleId widgetsBundleId, List widgetFqns, User user) throws Exception {
+ widgetTypeService.updateWidgetsBundleWidgetFqns(user.getTenantId(), widgetsBundleId, widgetFqns);
+ autoCommit(user, widgetsBundleId);
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/TbWidgetsBundleService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/TbWidgetsBundleService.java
index d60bc66d66..7a954cdda8 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/TbWidgetsBundleService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/TbWidgetsBundleService.java
@@ -15,8 +15,18 @@
*/
package org.thingsboard.server.service.entitiy.widgets.bundle;
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.id.WidgetTypeId;
+import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.service.entitiy.SimpleTbEntityService;
+import java.util.List;
+
public interface TbWidgetsBundleService extends SimpleTbEntityService {
+
+ void updateWidgetsBundleWidgetTypes(WidgetsBundleId widgetsBundleId, List widgetTypeIds, User user) throws Exception;
+
+ void updateWidgetsBundleWidgetFqns(WidgetsBundleId widgetsBundleId, List widgetFqns, User user) throws Exception;
+
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/type/DefaultWidgetTypeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/type/DefaultWidgetTypeService.java
new file mode 100644
index 0000000000..1d40e9630c
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/type/DefaultWidgetTypeService.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.entitiy.widgets.type;
+
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.StringUtils;
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.widget.WidgetType;
+import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
+import org.thingsboard.server.dao.widget.WidgetTypeService;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+
+@Service
+@TbCoreComponent
+@AllArgsConstructor
+public class DefaultWidgetTypeService extends AbstractTbEntityService implements TbWidgetTypeService {
+
+ private final WidgetTypeService widgetTypeService;
+
+ @Override
+ public WidgetTypeDetails save(WidgetTypeDetails entity, User user) throws Exception {
+ return this.save(entity, false, user);
+ }
+
+ @Override
+ public WidgetTypeDetails save(WidgetTypeDetails widgetTypeDetails, boolean updateExistingByFqn, User user) throws Exception {
+ TenantId tenantId = widgetTypeDetails.getTenantId();
+ if (widgetTypeDetails.getId() == null && StringUtils.isNotEmpty(widgetTypeDetails.getFqn()) && updateExistingByFqn) {
+ WidgetType widgetType = widgetTypeService.findWidgetTypeByTenantIdAndFqn(tenantId, widgetTypeDetails.getFqn());
+ if (widgetType != null) {
+ widgetTypeDetails.setId(widgetType.getId());
+ }
+ }
+ ActionType actionType = widgetTypeDetails.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
+ try {
+ WidgetTypeDetails savedWidgetTypeDetails = checkNotNull(widgetTypeService.saveWidgetType(widgetTypeDetails));
+ autoCommit(user, savedWidgetTypeDetails.getId());
+ notificationEntityService.logEntityAction(tenantId, savedWidgetTypeDetails.getId(), savedWidgetTypeDetails,
+ null, actionType, user);
+ return savedWidgetTypeDetails;
+ } catch (Exception e) {
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGET_TYPE), widgetTypeDetails, actionType, user, e);
+ throw e;
+ }
+ }
+
+ @Override
+ public void delete(WidgetTypeDetails widgetTypeDetails, User user) {
+ ActionType actionType = ActionType.DELETED;
+ TenantId tenantId = widgetTypeDetails.getTenantId();
+ try {
+ widgetTypeService.deleteWidgetType(widgetTypeDetails.getTenantId(), widgetTypeDetails.getId());
+ notificationEntityService.logEntityAction(tenantId, widgetTypeDetails.getId(), widgetTypeDetails, null, actionType, user);
+ } catch (Exception e) {
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGET_TYPE), actionType, user, e, widgetTypeDetails.getId());
+ throw e;
+ }
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/type/TbWidgetTypeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/type/TbWidgetTypeService.java
new file mode 100644
index 0000000000..8951b49552
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/type/TbWidgetTypeService.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.widgets.type;
+
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
+import org.thingsboard.server.service.entitiy.SimpleTbEntityService;
+
+public interface TbWidgetTypeService extends SimpleTbEntityService {
+
+ WidgetTypeDetails save(WidgetTypeDetails widgetTypeDetails, boolean updateExistingByFqn, User user) throws Exception;
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java
new file mode 100644
index 0000000000..4e83aa0060
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/InMemoryHouseKeeperServiceService.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.housekeeper;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.event.TransactionalEventListener;
+import org.thingsboard.common.util.ThingsBoardThreadFactory;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.id.AlarmId;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
+import org.thingsboard.server.dao.housekeeper.HouseKeeperService;
+import org.thingsboard.server.service.entitiy.alarm.TbAlarmService;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class InMemoryHouseKeeperServiceService implements HouseKeeperService {
+
+ final TbAlarmService alarmService;
+
+ ListeningExecutorService executor;
+
+ AtomicInteger queueSize = new AtomicInteger();
+ AtomicInteger totalProcessedCounter = new AtomicInteger();
+
+ @PostConstruct
+ public void init() {
+ log.debug("Starting HouseKeeper service");
+ executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("housekeeper")));
+ }
+
+ @PreDestroy
+ public void destroy() {
+ if (executor != null) {
+ log.debug("Stopping HouseKeeper service");
+ executor.shutdown();
+ }
+ }
+
+ @TransactionalEventListener(fallbackExecution = true)
+ public void handleEvent(DeleteEntityEvent> event) {
+ log.trace("[{}] DeleteEntityEvent handler: {}", event.getTenantId(), event);
+ EntityId entityId = event.getEntityId();
+ if (EntityType.USER.equals(entityId.getEntityType())) {
+ unassignDeletedUserAlarms(event.getTenantId(), (User) event.getEntity(), event.getTs());
+ }
+ }
+
+ @Override
+ public ListenableFuture> unassignDeletedUserAlarms(TenantId tenantId, User user, long unassignTs) {
+ log.debug("[{}][{}] unassignDeletedUserAlarms submitting, pending queue size: {} ", tenantId, user.getId().getId(), queueSize.get());
+ queueSize.incrementAndGet();
+ ListenableFuture> future = executor.submit(() -> alarmService.unassignDeletedUserAlarms(tenantId, user, unassignTs));
+ Futures.addCallback(future, new FutureCallback<>() {
+ @Override
+ public void onSuccess(List alarmIds) {
+ queueSize.decrementAndGet();
+ totalProcessedCounter.incrementAndGet();
+ log.debug("[{}][{}] unassignDeletedUserAlarms finished, pending queue size: {}, total processed count: {} ",
+ tenantId, user.getId().getId(), queueSize.get(), totalProcessedCounter.get());
+ }
+
+ @Override
+ public void onFailure(@NotNull Throwable throwable) {
+ queueSize.decrementAndGet();
+ totalProcessedCounter.incrementAndGet();
+ log.error("[{}][{}] unassignDeletedUserAlarms failed, pending queue size: {}, total processed count: {}",
+ tenantId, user.getId().getId(), queueSize.get(), totalProcessedCounter.get(), throwable);
+ }
+ }, MoreExecutors.directExecutor());
+ return future;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
index c0396e2d9e..3286d3ef6a 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
@@ -99,6 +99,7 @@ import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.dao.user.UserService;
+import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
@@ -114,13 +115,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
@@ -135,6 +137,9 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
@Autowired
private AdminSettingsService adminSettingsService;
+ @Autowired
+ private WidgetTypeService widgetTypeService;
+
@Autowired
private WidgetsBundleService widgetsBundleService;
@@ -484,6 +489,10 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public void deleteSystemWidgetBundle(String bundleAlias) throws Exception {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(TenantId.SYS_TENANT_ID, bundleAlias);
if (widgetsBundle != null) {
+ var widgetTypes = widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID, widgetsBundle.getId());
+ for (var widgetType : widgetTypes) {
+ widgetTypeService.deleteWidgetType(TenantId.SYS_TENANT_ID, widgetType.getId());
+ }
widgetsBundleService.deleteWidgetsBundle(TenantId.SYS_TENANT_ID, widgetsBundle.getId());
}
}
@@ -511,6 +520,10 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
this.deleteSystemWidgetBundle("navigation_widgets");
this.deleteSystemWidgetBundle("edge_widgets");
this.deleteSystemWidgetBundle("home_page_widgets");
+ this.deleteSystemWidgetBundle("entity_widgets");
+ this.deleteSystemWidgetBundle("html_widgets");
+ this.deleteSystemWidgetBundle("tables");
+ this.deleteSystemWidgetBundle("count_widgets");
installScripts.loadSystemWidgets();
}
@@ -524,7 +537,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/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
index 36ec2b9b78..7f0b70cb27 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
@@ -46,7 +46,9 @@ import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.Base64;
+import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@@ -70,6 +72,7 @@ public class InstallScripts {
public static final String DEVICE_PROFILE_DIR = "device_profile";
public static final String DEMO_DIR = "demo";
public static final String RULE_CHAINS_DIR = "rule_chains";
+ public static final String WIDGET_TYPES_DIR = "widget_types";
public static final String WIDGET_BUNDLES_DIR = "widget_bundles";
public static final String OAUTH2_CONFIG_TEMPLATES_DIR = "oauth2_config_templates";
public static final String DASHBOARDS_DIR = "dashboards";
@@ -100,15 +103,15 @@ public class InstallScripts {
@Autowired
private ResourceService resourceService;
- private Path getTenantRuleChainsDir() {
+ Path getTenantRuleChainsDir() {
return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
}
- private Path getDeviceProfileDefaultRuleChainTemplateFilePath() {
+ Path getDeviceProfileDefaultRuleChainTemplateFilePath() {
return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, DEVICE_PROFILE_DIR, "rule_chain_template.json");
}
- private Path getEdgeRuleChainsDir() {
+ Path getEdgeRuleChainsDir() {
return Paths.get(getDataDir(), JSON_DIR, EDGE_DIR, RULE_CHAINS_DIR);
}
@@ -144,8 +147,8 @@ public class InstallScripts {
}
private void loadRuleChainsFromPath(TenantId tenantId, Path ruleChainsPath) throws IOException {
- try (DirectoryStream dirStream = Files.newDirectoryStream(ruleChainsPath, path -> path.toString().endsWith(InstallScripts.JSON_EXT))) {
- dirStream.forEach(
+ findRuleChainsFromPath(ruleChainsPath)
+ .forEach(
path -> {
try {
createRuleChainFromFile(tenantId, path, null);
@@ -153,9 +156,15 @@ public class InstallScripts {
log.error("Unable to load rule chain from json: [{}]", path.toString());
throw new RuntimeException("Unable to load rule chain from json", e);
}
- }
- );
+ });
+ }
+
+ List findRuleChainsFromPath(Path ruleChainsPath) throws IOException {
+ List paths = new ArrayList<>();
+ try (DirectoryStream dirStream = Files.newDirectoryStream(ruleChainsPath, path -> path.toString().endsWith(InstallScripts.JSON_EXT))) {
+ dirStream.forEach(paths::add);
}
+ return paths;
}
public RuleChain createDefaultRuleChain(TenantId tenantId, String ruleChainName) throws IOException {
@@ -180,6 +189,23 @@ public class InstallScripts {
}
public void loadSystemWidgets() throws Exception {
+ Path widgetTypesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_TYPES_DIR);
+ if (Files.exists(widgetTypesDir)) {
+ try (DirectoryStream dirStream = Files.newDirectoryStream(widgetTypesDir, path -> path.toString().endsWith(JSON_EXT))) {
+ dirStream.forEach(
+ path -> {
+ try {
+ JsonNode widgetTypeJson = JacksonUtil.toJsonNode(path.toFile());
+ WidgetTypeDetails widgetTypeDetails = JacksonUtil.treeToValue(widgetTypeJson, WidgetTypeDetails.class);
+ widgetTypeService.saveWidgetType(widgetTypeDetails);
+ } catch (Exception e) {
+ log.error("Unable to load widget type from json: [{}]", path.toString());
+ throw new RuntimeException("Unable to load widget type from json", e);
+ }
+ }
+ );
+ }
+ }
Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR);
try (DirectoryStream dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
@@ -189,19 +215,29 @@ public class InstallScripts {
JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle");
WidgetsBundle widgetsBundle = JacksonUtil.treeToValue(widgetsBundleJson, WidgetsBundle.class);
WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle);
- JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes");
- widgetTypesArrayJson.forEach(
- widgetTypeJson -> {
- try {
- WidgetTypeDetails widgetTypeDetails = JacksonUtil.treeToValue(widgetTypeJson, WidgetTypeDetails.class);
- widgetTypeDetails.setBundleAlias(savedWidgetsBundle.getAlias());
- widgetTypeService.saveWidgetType(widgetTypeDetails);
- } catch (Exception e) {
- log.error("Unable to load widget type from json: [{}]", path.toString());
- throw new RuntimeException("Unable to load widget type from json", e);
+ List widgetTypeFqns = new ArrayList<>();
+ if (widgetsBundleDescriptorJson.has("widgetTypes")) {
+ JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes");
+ widgetTypesArrayJson.forEach(
+ widgetTypeJson -> {
+ try {
+ WidgetTypeDetails widgetTypeDetails = JacksonUtil.treeToValue(widgetTypeJson, WidgetTypeDetails.class);
+ var savedWidgetType = widgetTypeService.saveWidgetType(widgetTypeDetails);
+ widgetTypeFqns.add(savedWidgetType.getFqn());
+ } catch (Exception e) {
+ log.error("Unable to load widget type from json: [{}]", path.toString());
+ throw new RuntimeException("Unable to load widget type from json", e);
+ }
}
- }
- );
+ );
+ }
+ if (widgetsBundleDescriptorJson.has("widgetTypeFqns")) {
+ JsonNode widgetFqnsArrayJson = widgetsBundleDescriptorJson.get("widgetTypeFqns");
+ widgetFqnsArrayJson.forEach(fqnJson -> {
+ widgetTypeFqns.add(fqnJson.asText());
+ });
+ }
+ widgetTypeService.updateWidgetsBundleWidgetFqns(TenantId.SYS_TENANT_ID, savedWidgetsBundle.getId(), widgetTypeFqns);
} catch (Exception e) {
log.error("Unable to load widgets bundle from json: [{}]", path.toString());
throw new RuntimeException("Unable to load widgets bundle from json", e);
@@ -268,7 +304,7 @@ public class InstallScripts {
}
public void loadSystemLwm2mResources() {
- Path resourceLwm2mPath = Paths.get(dataDir, MODELS_LWM2M_DIR);
+ Path resourceLwm2mPath = Paths.get(getDataDir(), MODELS_LWM2M_DIR);
try (DirectoryStream dirStream = Files.newDirectoryStream(resourceLwm2mPath, path -> path.toString().endsWith(InstallScripts.XML_EXT))) {
dirStream.forEach(
path -> {
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..c02b7e9cc1 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
@@ -731,8 +731,8 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
break;
case "3.5.1":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
- log.info("Updating schema ...");
if (isOldSchema(conn, 3005001)) {
+ log.info("Updating schema ...");
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.5.1", SCHEMA_UPDATE_SQL);
loadSql(schemaUpdateFile, conn);
@@ -756,10 +756,38 @@ 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("UPDATE rule_node SET " +
+ "configuration = (configuration::jsonb || '{\"updateAttributesOnlyOnValueChange\": \"false\"}'::jsonb)::varchar, " +
+ "configuration_version = 1 " +
+ "WHERE type = 'org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode' AND configuration_version < 1;");
+ } 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;");
+ conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3006000;");
+ log.info("Schema updated to version 3.6.0.");
+ } else {
+ log.info("Skip schema re-update to version 3.6.0. Use env flag 'SKIP_SCHEMA_VERSION_CHECK' to force the re-update.");
+ }
+ } catch (Exception e) {
+ log.error("Failed updating schema!!!", e);
+ }
+ break;
+ case "3.6.0":
+ try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
+ if (isOldSchema(conn, 3006000)) {
+ log.info("Updating schema ...");
+ schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.6.0", SCHEMA_UPDATE_SQL);
+ loadSql(schemaUpdateFile, conn);
+ conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3006001;");
+ log.info("Schema updated to version 3.6.1.");
+ } else {
+ log.info("Skip schema re-update to version 3.6.1. Use env flag 'SKIP_SCHEMA_VERSION_CHECK' to force the re-update.");
}
- log.info("Schema updated.");
} catch (Exception e) {
log.error("Failed updating schema!!!", e);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
index dafccfdad6..8c3b78040b 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
@@ -27,7 +27,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
-import org.thingsboard.rule.engine.api.TbVersionedNode;
+import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
@@ -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;
@@ -77,6 +78,7 @@ import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;
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.sql.JpaExecutorService;
import org.thingsboard.server.dao.sql.device.DeviceProfileRepository;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
@@ -87,9 +89,7 @@ import org.thingsboard.server.service.install.SystemDataLoaderService;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
@@ -102,6 +102,8 @@ import static org.thingsboard.server.common.data.StringUtils.isBlank;
@Slf4j
public class DefaultDataUpdateService implements DataUpdateService {
+ private static final int MAX_PENDING_SAVE_RULE_NODE_FUTURES = 100;
+
@Autowired
private TenantService tenantService;
@@ -154,6 +156,9 @@ public class DefaultDataUpdateService implements DataUpdateService {
@Autowired
private EdgeEventDao edgeEventDao;
+ @Autowired
+ JpaExecutorService jpaExecutorService;
+
@Override
public void updateData(String fromVersion) throws Exception {
switch (fromVersion) {
@@ -205,7 +210,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
migrateEdgeEvents("Starting edge events migration. ");
break;
case "3.5.1":
- log.info("Updating data from version 3.5.1 to 3.5.2 ...");
+ log.info("Updating data from version 3.5.1 to 3.6.0 ...");
migrateEdgeEvents("Starting edge events migration - adding seq_id column. ");
break;
default:
@@ -226,49 +231,67 @@ public class DefaultDataUpdateService implements DataUpdateService {
@Override
public void upgradeRuleNodes() {
try {
- log.info("Lookup rule nodes to upgrade ...");
+ var futures = new ArrayList>(100);
+ int totalRuleNodesUpgraded = 0;
+ log.info("Starting rule nodes upgrade ...");
var nodeClassToVersionMap = componentDiscoveryService.getVersionedNodes();
- log.info("Found {} versioned nodes to check for upgrade!", nodeClassToVersionMap.size());
- nodeClassToVersionMap.forEach(clazz -> {
- var ruleNodeType = clazz.getClassName();
- var ruleNodeTypeForLogs = clazz.getSimpleName();
- var toVersion = clazz.getCurrentVersion();
- log.info("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion);
+ log.debug("Found {} versioned nodes to check for upgrade!", nodeClassToVersionMap.size());
+ for (var ruleNodeClassInfo : nodeClassToVersionMap) {
+ var ruleNodeType = ruleNodeClassInfo.getClassName();
+ var ruleNodeTypeForLogs = ruleNodeClassInfo.getSimpleName();
+ var toVersion = ruleNodeClassInfo.getCurrentVersion();
+ log.debug("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion);
var ruleNodesToUpdate = new PageDataIterable<>(
pageLink -> ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeType, toVersion, pageLink), 1024
);
if (Iterables.isEmpty(ruleNodesToUpdate)) {
- log.info("There are no active nodes with type: {}, or all nodes with this type already set to latest version!", ruleNodeTypeForLogs);
+ log.debug("There are no active nodes with type: {}, or all nodes with this type already set to latest version!", ruleNodeTypeForLogs);
} else {
for (var ruleNode : ruleNodesToUpdate) {
var ruleNodeId = ruleNode.getId();
var oldConfiguration = ruleNode.getConfiguration();
int fromVersion = ruleNode.getConfigurationVersion();
- log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
+ log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion);
try {
- var tbVersionedNode = (TbVersionedNode) clazz.getClazz().getDeclaredConstructor().newInstance();
+ var tbVersionedNode = (TbNode) ruleNodeClassInfo.getClazz().getDeclaredConstructor().newInstance();
TbPair upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration);
if (upgradeRuleNodeConfigurationResult.getFirst()) {
ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond());
}
ruleNode.setConfigurationVersion(toVersion);
- ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode);
- log.info("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
- ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion);
+ futures.add(jpaExecutorService.submit(() -> {
+ ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode);
+ log.debug("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
+ ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion);
+ }));
+ if (futures.size() >= MAX_PENDING_SAVE_RULE_NODE_FUTURES) {
+ log.info("{} upgraded rule nodes so far ...",
+ totalRuleNodesUpgraded += awaitFuturesToCompleteAndGetCount(futures));
+ futures.clear();
+ }
} catch (Exception e) {
log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ",
ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion, e);
}
}
}
- });
- log.info("Finished rule nodes upgrade!");
+ }
+ log.info("Finished rule nodes upgrade. Upgraded rule nodes count: {}",
+ totalRuleNodesUpgraded + awaitFuturesToCompleteAndGetCount(futures));
} catch (Exception e) {
log.error("Unexpected error during rule nodes upgrade: ", e);
}
}
+ private int awaitFuturesToCompleteAndGetCount(List> futures) {
+ try {
+ return Futures.allAsList(futures).get().size();
+ } catch (ExecutionException | InterruptedException e) {
+ throw new RuntimeException("Failed to process save rule nodes requests due to: ", e);
+ }
+ }
+
private final PaginatedUpdater deviceProfileEntityDynamicConditionsUpdater =
new PaginatedUpdater<>() {
@@ -502,7 +525,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 053a766b7b..41ad67b55c 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 jakarta.xml.bind.DatatypeConverter;
@@ -364,6 +363,8 @@ public class DefaultMailService implements MailService {
return valueInM + " out of " + thresholdInM + " allowed messages";
case JS_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed JavaScript functions";
+ case TBEL_EXEC_COUNT:
+ return valueInM + " out of " + thresholdInM + " allowed Tbel functions";
case RE_EXEC_COUNT:
return valueInM + " out of " + thresholdInM + " allowed Rule Engine messages";
case EMAIL_EXEC_COUNT:
@@ -384,6 +385,8 @@ public class DefaultMailService implements MailService {
return recordState.getValueAsString() + " messages";
case JS_EXEC_COUNT:
return "JavaScript functions " + recordState.getValueAsString() + " times";
+ case TBEL_EXEC_COUNT:
+ return "TBEL functions " + recordState.getValueAsString() + " times";
case RE_EXEC_COUNT:
return recordState.getValueAsString() + " Rule Engine messages";
case EMAIL_EXEC_COUNT:
diff --git a/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java b/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java
index e8e9271998..76e080c7ba 100644
--- a/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java
+++ b/application/src/main/java/org/thingsboard/server/service/mail/TbMailSender.java
@@ -23,18 +23,18 @@ import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
-import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
+import org.springframework.mail.MailException;
+import org.springframework.mail.MailSendException;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.StringUtils;
-import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
-import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.mail.MailOauth2Provider;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
+import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import java.time.Duration;
import java.time.Instant;
@@ -50,6 +50,7 @@ public class TbMailSender extends JavaMailSenderImpl {
private static final String MAIL_PROP = "mail.";
private final TbMailContextComponent ctx;
private final Lock lock;
+
private final Boolean oauth2Enabled;
private volatile String accessToken;
private volatile long tokenExpires;
@@ -70,14 +71,39 @@ public class TbMailSender extends JavaMailSenderImpl {
setJavaMailProperties(createJavaMailProperties(jsonConfig));
}
- @SneakyThrows
+ public Boolean getOauth2Enabled() {
+ return oauth2Enabled;
+ }
+
+ public long getTokenExpires() {
+ return tokenExpires;
+ }
+
+ @Override
+ protected void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) throws MailException {
+ updateOauth2PasswordIfExpired();
+ doSendSuper(mimeMessages, originalMessages);
+ }
+
+ public void doSendSuper(MimeMessage[] mimeMessages, Object[] originalMessages) {
+ super.doSend(mimeMessages, originalMessages);
+ }
+
@Override
- public void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) {
- if (oauth2Enabled && (System.currentTimeMillis() > tokenExpires)){
+ public void testConnection() throws MessagingException {
+ updateOauth2PasswordIfExpired();
+ testConnectionSuper();
+ }
+
+ public void testConnectionSuper() throws MessagingException {
+ super.testConnection();
+ }
+
+ public void updateOauth2PasswordIfExpired() {
+ if (getOauth2Enabled() && (System.currentTimeMillis() > getTokenExpires())){
refreshAccessToken();
setPassword(accessToken);
}
- super.doSend(mimeMessages, originalMessages);
}
private Properties createJavaMailProperties(JsonNode jsonConfig) {
@@ -125,10 +151,10 @@ public class TbMailSender extends JavaMailSenderImpl {
return javaMailProperties;
}
- public void refreshAccessToken() throws ThingsboardException {
+ public void refreshAccessToken() {
lock.lock();
try {
- if (System.currentTimeMillis() > tokenExpires) {
+ if (System.currentTimeMillis() > getTokenExpires()) {
AdminSettings settings = ctx.getAdminSettingsService().findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
JsonNode jsonValue = settings.getJsonValue();
@@ -151,8 +177,8 @@ public class TbMailSender extends JavaMailSenderImpl {
tokenExpires = System.currentTimeMillis() + (tokenResponse.getExpiresInSeconds().intValue() * 1000);
}
} catch (Exception e) {
- log.warn("Unable to retrieve access token: {}", e.getMessage());
- throw new ThingsboardException("Error while retrieving access token: " + e.getMessage(), ThingsboardErrorCode.GENERAL);
+ log.error("Unable to retrieve access token: {}", e.getMessage());
+ throw new RuntimeException("Error while retrieving access token: " + e.getMessage());
} finally {
lock.unlock();
}
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..f6c77691da 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
@@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.NotificationRuleId;
@@ -39,9 +40,12 @@ 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.settings.UserNotificationSettings;
+import org.thingsboard.server.common.data.notification.targets.MicrosoftTeamsNotificationTargetConfig;
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;
+import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
@@ -163,16 +167,54 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
.settings(settings)
.build();
+ processNotificationRequestAsync(ctx, targets, callback);
+ return request;
+ }
+
+ @Override
+ public void sendGeneralWebNotification(TenantId tenantId, UsersFilter recipients, NotificationTemplate template) {
+ NotificationTarget target = new NotificationTarget();
+ target.setTenantId(tenantId);
+ PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig();
+ targetConfig.setUsersFilter(recipients);
+ target.setConfiguration(targetConfig);
+
+ NotificationRequest notificationRequest = NotificationRequest.builder()
+ .tenantId(tenantId)
+ .template(template)
+ .targets(List.of(EntityId.NULL_UUID)) // this is temporary and will be removed when 'create from scratch' functionality is implemented for recipients
+ .status(NotificationRequestStatus.PROCESSING)
+ .build();
+ try {
+ notificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest);
+ NotificationProcessingContext ctx = NotificationProcessingContext.builder()
+ .tenantId(tenantId)
+ .request(notificationRequest)
+ .deliveryMethods(Set.of(NotificationDeliveryMethod.WEB))
+ .template(template)
+ .build();
+
+ processNotificationRequestAsync(ctx, List.of(target), null);
+ } catch (Exception e) {
+ log.error("Failed to process notification request for recipients {} for template '{}'", recipients, template.getName(), e);
+ }
+ }
+
+ private void processNotificationRequestAsync(NotificationProcessingContext ctx, List targets, Consumer callback) {
notificationExecutor.submit(() -> {
+ NotificationRequestId requestId = ctx.getRequest().getId();
for (NotificationTarget target : targets) {
- processForTarget(target, ctx);
+ try {
+ processForTarget(target, ctx);
+ } catch (Exception e) {
+ log.error("[{}] Failed to process notification request for target {}", requestId, target.getId(), e);
+ }
}
-
- NotificationRequestId requestId = ctx.getRequest().getId();
log.debug("[{}] Notification request processing is finished", requestId);
+
NotificationRequestStats stats = ctx.getStats();
try {
- notificationRequestService.updateNotificationRequest(tenantId, requestId, NotificationRequestStatus.SENT, stats);
+ notificationRequestService.updateNotificationRequest(ctx.getTenantId(), requestId, NotificationRequestStatus.SENT, stats);
} catch (Exception e) {
log.error("[{}] Failed to update stats for notification request", requestId, e);
}
@@ -185,8 +227,6 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
}
}
});
-
- return request;
}
private void processForTarget(NotificationTarget target, NotificationProcessingContext ctx) {
@@ -210,6 +250,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 +282,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 +306,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/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
index 76631aaa95..53ef38d96a 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
@@ -32,10 +32,10 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
+import org.thingsboard.server.common.data.HasRuleEngineProfile;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
-import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AssetId;
@@ -178,15 +178,8 @@ public class DefaultTbClusterService implements TbClusterService {
return;
}
} else {
- if (entityId.getEntityType().equals(EntityType.DEVICE)) {
- tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())));
- } else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) {
- tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId())));
- } else if (entityId.getEntityType().equals(EntityType.ASSET)) {
- tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetId(entityId.getId())));
- } else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) {
- tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId())));
- }
+ HasRuleEngineProfile ruleEngineProfile = getRuleEngineProfileForEntityOrElseNull(tenantId, entityId);
+ tbMsg = transformMsg(tbMsg, ruleEngineProfile);
}
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId);
log.trace("PUSHING msg: {} to:{}", tbMsg, tpi);
@@ -198,34 +191,33 @@ public class DefaultTbClusterService implements TbClusterService {
toRuleEngineMsgs.incrementAndGet();
}
- private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) {
- if (deviceProfile != null) {
- RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId();
- String targetQueueName = deviceProfile.getDefaultQueueName();
- tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName);
+ private HasRuleEngineProfile getRuleEngineProfileForEntityOrElseNull(TenantId tenantId, EntityId entityId) {
+ if (entityId.getEntityType().equals(EntityType.DEVICE)) {
+ return deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
+ } else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) {
+ return deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId()));
+ } else if (entityId.getEntityType().equals(EntityType.ASSET)) {
+ return assetProfileCache.get(tenantId, new AssetId(entityId.getId()));
+ } else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) {
+ return assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId()));
}
- return tbMsg;
- }
-
- private TbMsg transformMsg(TbMsg tbMsg, AssetProfile assetProfile) {
- if (assetProfile != null) {
- RuleChainId targetRuleChainId = assetProfile.getDefaultRuleChainId();
- String targetQueueName = assetProfile.getDefaultQueueName();
- tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName);
- }
- return tbMsg;
- }
-
- private TbMsg transformMsg(TbMsg tbMsg, RuleChainId targetRuleChainId, String targetQueueName) {
- boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
- boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
-
- if (isRuleChainTransform && isQueueTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
- } else if (isRuleChainTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId);
- } else if (isQueueTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName);
+ return null;
+ }
+ private TbMsg transformMsg(TbMsg tbMsg, HasRuleEngineProfile ruleEngineProfile) {
+ if (ruleEngineProfile != null) {
+ RuleChainId targetRuleChainId = ruleEngineProfile.getDefaultRuleChainId();
+ String targetQueueName = ruleEngineProfile.getDefaultQueueName();
+
+ boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
+ boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
+
+ if (isRuleChainTransform && isQueueTransform) {
+ tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
+ } else if (isRuleChainTransform) {
+ tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId);
+ } else if (isQueueTransform) {
+ tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName);
+ }
}
return tbMsg;
}
@@ -466,11 +458,6 @@ public class DefaultTbClusterService implements TbClusterService {
@Override
public void onDeviceUpdated(Device device, Device old) {
- onDeviceUpdated(device, old, true);
- }
-
- @Override
- public void onDeviceUpdated(Device device, Device old, boolean notifyEdge) {
var created = old == null;
broadcastEntityChangeToTransport(device.getTenantId(), device.getId(), device, null);
if (old != null) {
@@ -485,9 +472,6 @@ public class DefaultTbClusterService implements TbClusterService {
broadcastEntityStateChangeEvent(device.getTenantId(), device.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
sendDeviceStateServiceEvent(device.getTenantId(), device.getId(), created, !created, false);
otaPackageStateService.update(device, old);
- if (!created && notifyEdge) {
- sendNotificationMsgToEdge(device.getTenantId(), null, device.getId(), null, null, EdgeEventActionType.UPDATED);
- }
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
index 4abce4fb0a..b6254af229 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
@@ -24,18 +24,23 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
+import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
+import org.thingsboard.server.common.data.event.ErrorEvent;
+import org.thingsboard.server.common.data.event.Event;
+import org.thingsboard.server.common.data.event.LifecycleEvent;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
-import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger;
+import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
@@ -45,7 +50,9 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto;
import org.thingsboard.server.gen.transport.TransportProtos.EdgeNotificationMsgProto;
+import org.thingsboard.server.gen.transport.TransportProtos.ErrorEventProto;
import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto;
+import org.thingsboard.server.gen.transport.TransportProtos.LifecycleEventProto;
import org.thingsboard.server.gen.transport.TransportProtos.LocalSubscriptionServiceMsgProto;
import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionMgrMsgProto;
import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmDeleteProto;
@@ -64,7 +71,6 @@ import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
-import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
@@ -275,6 +281,10 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService callback.onSuccess(),
+ callback::onFailure,
+ actorContext.getDbCallbackExecutor());
+ }
+
private void throwNotHandled(Object msg, TbCallback callback) {
log.warn("Message not handled: {}", msg);
callback.onFailure(new RuntimeException("Message not handled!"));
}
+ private TenantId toTenantId(long tenantIdMSB, long tenantIdLSB) {
+ return TenantId.fromUUID(new UUID(tenantIdMSB, tenantIdLSB));
+ }
+
@Override
protected void stopMainConsumers() {
if (mainConsumer != null) {
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
index 6ea73a39dd..809b1c66e8 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
@@ -23,11 +23,14 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.EntityIdFactory;
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.common.data.rpc.RpcError;
import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.gen.MsgProtos;
import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.common.msg.queue.RuleNodeInfo;
@@ -42,12 +45,14 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
+import org.thingsboard.server.queue.TbQueueAdmin;
import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.QueueKey;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
+import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.TbRuleEngineComponent;
@@ -98,6 +103,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
private boolean statsEnabled;
@Value("${queue.rule-engine.prometheus-stats.enabled:false}")
boolean prometheusStatsEnabled;
+ @Value("${queue.rule-engine.topic-deletion-delay:30}")
+ private int topicDeletionDelayInSec;
private final StatsFactory statsFactory;
private final TbRuleEngineSubmitStrategyFactory submitStrategyFactory;
@@ -107,6 +114,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
private final TbRuleEngineDeviceRpcService tbDeviceRpcService;
private final TbServiceInfoProvider serviceInfoProvider;
private final QueueService queueService;
+ private final TbQueueProducerProvider producerProvider;
+ private final TbQueueAdmin queueAdmin;
private final ConcurrentMap>> consumers = new ConcurrentHashMap<>();
private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>();
private final ConcurrentMap consumerStats = new ConcurrentHashMap<>();
@@ -127,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;
@@ -137,6 +147,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
this.statsFactory = statsFactory;
this.serviceInfoProvider = serviceInfoProvider;
this.queueService = queueService;
+ this.producerProvider = producerProvider;
+ this.queueAdmin = queueAdmin;
}
@PostConstruct
@@ -144,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 {
@@ -169,14 +183,20 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
@Override
protected void onTbApplicationEvent(PartitionChangeEvent event) {
if (event.getServiceType().equals(getServiceType())) {
- String serviceQueue = event.getQueueKey().getQueueName();
- log.info("[{}] Subscribing to partitions: {}", serviceQueue, event.getPartitions());
- if (!consumerConfigurations.get(event.getQueueKey()).isConsumerPerPartition()) {
- consumers.get(event.getQueueKey()).subscribe(event.getPartitions());
- } else {
- log.info("[{}] Subscribing consumer per partition: {}", serviceQueue, event.getPartitions());
- subscribeConsumerPerPartition(event.getQueueKey(), event.getPartitions());
- }
+ event.getPartitionsMap().forEach((queueKey, partitions) -> {
+ String serviceQueue = queueKey.getQueueName();
+ log.info("[{}] Subscribing to partitions: {}", serviceQueue, partitions);
+ Queue configuration = consumerConfigurations.get(queueKey);
+ if (configuration == null) {
+ return;
+ }
+ if (!configuration.isConsumerPerPartition()) {
+ consumers.get(queueKey).subscribe(partitions);
+ } else {
+ log.info("[{}] Subscribing consumer per partition: {}", serviceQueue, partitions);
+ subscribeConsumerPerPartition(queueKey, partitions);
+ }
+ });
}
}
@@ -229,7 +249,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();
}
@@ -277,9 +296,9 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
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