Browse Source

merge with develop/3.4

pull/6170/head
ShvaykaD 4 years ago
parent
commit
2c40bf13cf
  1. 4
      application/pom.xml
  2. 2
      application/src/main/conf/logback.xml
  3. 103
      application/src/main/data/upgrade/3.3.4/schema_update.sql
  4. 49
      application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql
  5. 4
      application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java
  6. 15
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  7. 56
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  8. 2
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  9. 67
      application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java
  10. 44
      application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
  11. 156
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  12. 24
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  13. 24
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  14. 42
      application/src/main/java/org/thingsboard/server/controller/AutoCommitController.java
  15. 119
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  16. 11
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  17. 12
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  18. 26
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  19. 85
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  20. 11
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  21. 18
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  22. 519
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  23. 27
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  24. 14
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  25. 21
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  26. 126
      application/src/main/java/org/thingsboard/server/controller/QueueController.java
  27. 37
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  28. 8
      application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
  29. 39
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  30. 5
      application/src/main/java/org/thingsboard/server/controller/TenantController.java
  31. 34
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  32. 2
      application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java
  33. 12
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  34. 32
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  35. 27
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  36. 67
      application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java
  37. 2
      application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java
  38. 8
      application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java
  39. 11
      application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java
  40. 76
      application/src/main/java/org/thingsboard/server/service/apiusage/DefaultRateLimitService.java
  41. 11
      application/src/main/java/org/thingsboard/server/service/apiusage/RateLimitService.java
  42. 4
      application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
  43. 10
      application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java
  44. 71
      application/src/main/java/org/thingsboard/server/service/device/ClaimDevicesServiceImpl.java
  45. 10
      application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
  46. 2
      application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
  47. 4
      application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
  48. 16
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  49. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  50. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
  51. 8
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java
  52. 77
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/OtaPackageMsgConstructor.java
  53. 75
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/QueueMsgConstructor.java
  54. 253
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
  55. 137
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
  56. 28
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructor.java
  57. 32
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java
  58. 165
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java
  59. 42
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java
  60. 7
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
  61. 47
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OtaPackagesEdgeEventFetcher.java
  62. 47
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/QueuesEdgeEventFetcher.java
  63. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetsBundlesEdgeEventFetcher.java
  64. 50
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
  65. 63
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/OtaPackageEdgeProcessor.java
  66. 63
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/QueueEdgeProcessor.java
  67. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RuleChainEdgeProcessor.java
  68. 58
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java
  69. 24
      application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
  70. 148
      application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java
  71. 166
      application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
  72. 11
      application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java
  73. 65
      application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
  74. 55
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
  75. 11
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
  76. 80
      application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
  77. 16
      application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java
  78. 24
      application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java
  79. 176
      application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
  80. 23
      application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java
  81. 169
      application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
  82. 28
      application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java
  83. 52
      application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java
  84. 6
      application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/TbDeviceProfileService.java
  85. 71
      application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
  86. 14
      application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java
  87. 49
      application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java
  88. 10
      application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java
  89. 232
      application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java
  90. 33
      application/src/main/java/org/thingsboard/server/service/entitiy/entityview/TbEntityViewService.java
  91. 67
      application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java
  92. 15
      application/src/main/java/org/thingsboard/server/service/entitiy/ota/TbOtaPackageService.java
  93. 60
      application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
  94. 57
      application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java
  95. 5
      application/src/main/java/org/thingsboard/server/service/entitiy/tenant/TbTenantService.java
  96. 25
      application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/DefaultTbTenantProfileService.java
  97. 26
      application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/TbTenantProfileService.java
  98. 22
      application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java
  99. 5
      application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java
  100. 33
      application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java

4
application/pom.xml

@ -69,6 +69,10 @@
<groupId>org.thingsboard.common</groupId>
<artifactId>cluster-api</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>version-control</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard.rule-engine</groupId>
<artifactId>rule-engine-components</artifactId>

2
application/src/main/conf/logback.xml

@ -36,6 +36,8 @@
<logger name="org.thingsboard.server" level="INFO" />
<logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" />
<logger name="org.apache.kafka.common.utils.AppInfoParser" level="WARN"/>
<logger name="org.apache.kafka.clients" level="WARN"/>
<root level="INFO">
<appender-ref ref="fileLogAppender"/>

103
application/src/main/data/upgrade/3.3.4/schema_update.sql

@ -14,6 +14,31 @@
-- limitations under the License.
--
ALTER TABLE device
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE device_profile
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE asset
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE rule_chain
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE rule_node
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE dashboard
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE customer
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE widgets_bundle
ADD COLUMN IF NOT EXISTS external_id UUID;
ALTER TABLE entity_view
ADD COLUMN IF NOT EXISTS external_id UUID;
CREATE INDEX IF NOT EXISTS idx_rule_node_external_id ON rule_node(rule_chain_id, external_id);
CREATE INDEX IF NOT EXISTS idx_rule_node_type ON rule_node(type);
ALTER TABLE admin_settings
ADD COLUMN IF NOT EXISTS tenant_id uuid NOT NULL DEFAULT '13814000-1dd2-11b2-8080-808080808080';
CREATE TABLE IF NOT EXISTS queue (
id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY,
created_time bigint NOT NULL,
@ -35,3 +60,81 @@ CREATE TABLE IF NOT EXISTS user_auth_settings (
user_id uuid UNIQUE NOT NULL CONSTRAINT fk_user_auth_settings_user_id REFERENCES tb_user(id),
two_fa_settings varchar
);
CREATE INDEX IF NOT EXISTS idx_api_usage_state_entity_id ON api_usage_state(entity_id);
ALTER TABLE tenant_profile DROP COLUMN IF EXISTS isolated_tb_core;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'device_external_id_unq_key') THEN
ALTER TABLE device ADD CONSTRAINT device_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'device_profile_external_id_unq_key') THEN
ALTER TABLE device_profile ADD CONSTRAINT device_profile_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'asset_external_id_unq_key') THEN
ALTER TABLE asset ADD CONSTRAINT asset_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'rule_chain_external_id_unq_key') THEN
ALTER TABLE rule_chain ADD CONSTRAINT rule_chain_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'dashboard_external_id_unq_key') THEN
ALTER TABLE dashboard ADD CONSTRAINT dashboard_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'customer_external_id_unq_key') THEN
ALTER TABLE customer ADD CONSTRAINT customer_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'widgets_bundle_external_id_unq_key') THEN
ALTER TABLE widgets_bundle ADD CONSTRAINT widgets_bundle_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'entity_view_external_id_unq_key') THEN
ALTER TABLE entity_view ADD CONSTRAINT entity_view_external_id_unq_key UNIQUE (tenant_id, external_id);
END IF;
END;
$$;

49
application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql

@ -1,49 +0,0 @@
--
-- Copyright © 2016-2022 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.
--
ALTER TABLE device_profile
ADD COLUMN IF NOT EXISTS default_queue_id uuid;
DO
$$
BEGIN
IF EXISTS
(SELECT column_name
FROM information_schema.columns
WHERE table_name = 'device_profile'
AND column_name = 'default_queue_name'
)
THEN
UPDATE device_profile
SET default_queue_id = q.id
FROM queue as q
WHERE default_queue_name = q.name;
END IF;
END
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_queue_device_profile') THEN
ALTER TABLE device_profile
ADD CONSTRAINT fk_default_queue_device_profile FOREIGN KEY (default_queue_id) REFERENCES queue (id);
END IF;
END;
$$;
ALTER TABLE device_profile
DROP COLUMN IF EXISTS default_queue_name;

4
application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java

@ -32,7 +32,9 @@ import java.util.Arrays;
"org.thingsboard.server.dao",
"org.thingsboard.server.common.stats",
"org.thingsboard.server.common.transport.config.ssl",
"org.thingsboard.server.cache"})
"org.thingsboard.server.cache",
"org.thingsboard.server.springfox"
})
public class ThingsboardInstallApplication {
private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name";

15
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -48,7 +48,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.audit.AuditLogService;
@ -77,9 +76,11 @@ import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.executors.ExternalCallExecutorService;
import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
@ -220,6 +221,11 @@ public class ActorSystemContext {
@Getter
private EntityViewService entityViewService;
@Lazy
@Autowired(required = false)
@Getter
private TbEntityViewService tbEntityViewService;
@Autowired
@Getter
private TelemetrySubscriptionService tsSubService;
@ -502,13 +508,8 @@ public class ActorSystemContext {
return partitionService.resolve(serviceType, tenantId, entityId);
}
public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) {
return partitionService.resolve(serviceType, queueId, tenantId, entityId);
}
@Deprecated
public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) {
return partitionService.resolve(serviceType, tenantId, entityId, queueName);
return partitionService.resolve(serviceType, queueName, tenantId, entityId);
}
public String getServiceId() {

56
application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java

@ -162,18 +162,11 @@ class DefaultTbContext implements TbContext {
}
@Override
@Deprecated
public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueue(tpi, tbMsg, onFailure, onSuccess);
}
@Override
public void enqueue(TbMsg tbMsg, QueueId queueId, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId);
enqueue(tpi, tbMsg, onFailure, onSuccess);
}
private void enqueue(TopicPartitionInfo tpi, TbMsg tbMsg, Consumer<Throwable> onFailure, Runnable onSuccess) {
if (!tbMsg.isValid()) {
log.trace("[{}] Skip invalid message: {}", getTenantId(), tbMsg);
@ -223,35 +216,30 @@ class DefaultTbContext implements TbContext {
}
@Override
public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId);
enqueueForTellNext(tpi, queueId, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueueForTellNext(tpi, queueName, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
}
@Override
public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId);
enqueueForTellNext(tpi, queueId, tbMsg, relationTypes, null, onSuccess, onFailure);
}
private TopicPartitionInfo resolvePartition(TbMsg tbMsg, QueueId queueId) {
return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueId, getTenantId(), tbMsg.getOriginator());
public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueueForTellNext(tpi, queueName, tbMsg, relationTypes, null, onSuccess, onFailure);
}
@Deprecated
private TopicPartitionInfo resolvePartition(TbMsg tbMsg, String queueName) {
return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
}
private TopicPartitionInfo resolvePartition(TbMsg tbMsg) {
return resolvePartition(tbMsg, tbMsg.getQueueId());
return resolvePartition(tbMsg, tbMsg.getQueueName());
}
private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg source, Set<String> relationTypes, String failureMessage, Runnable onSuccess, Consumer<Throwable> onFailure) {
enqueueForTellNext(tpi, source.getQueueId(), source, relationTypes, failureMessage, onSuccess, onFailure);
enqueueForTellNext(tpi, source.getQueueName(), source, relationTypes, failureMessage, onSuccess, onFailure);
}
private void enqueueForTellNext(TopicPartitionInfo tpi, QueueId queueId, TbMsg source, Set<String> relationTypes, String failureMessage, Runnable onSuccess, Consumer<Throwable> onFailure) {
private void enqueueForTellNext(TopicPartitionInfo tpi, String queueName, TbMsg source, Set<String> relationTypes, String failureMessage, Runnable onSuccess, Consumer<Throwable> onFailure) {
if (!source.isValid()) {
log.trace("[{}] Skip invalid message: {}", getTenantId(), source);
if (onFailure != null) {
@ -261,7 +249,7 @@ class DefaultTbContext implements TbContext {
}
RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId();
RuleNodeId ruleNodeId = nodeCtx.getSelf().getId();
TbMsg tbMsg = TbMsg.newMsg(source, queueId, ruleChainId, ruleNodeId);
TbMsg tbMsg = TbMsg.newMsg(source, queueName, ruleChainId, ruleNodeId);
TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder()
.setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
.setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
@ -320,13 +308,13 @@ class DefaultTbContext implements TbContext {
}
@Override
public TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueId, type, originator, null, metaData, data);
public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueName, type, originator, null, metaData, data);
}
@Override
public TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return TbMsg.newMsg(queueId, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
public TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
}
@Override
@ -340,17 +328,17 @@ class DefaultTbContext implements TbContext {
public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) {
RuleChainId ruleChainId = null;
QueueId queueId = null;
String queueName = null;
if (device.getDeviceProfileId() != null) {
DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId());
if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", device.getDeviceProfileId());
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
queueId = deviceProfile.getDefaultQueueId();
queueName = deviceProfile.getDefaultQueueName();
}
}
return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueId, ruleChainId);
return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueName, ruleChainId);
}
public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) {
@ -359,7 +347,7 @@ class DefaultTbContext implements TbContext {
public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) {
RuleChainId ruleChainId = null;
QueueId queueId = null;
String queueName = null;
if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) {
DeviceId deviceId = new DeviceId(alarm.getOriginator().getId());
DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId);
@ -367,10 +355,10 @@ class DefaultTbContext implements TbContext {
log.warn("[{}] Device profile is null!", deviceId);
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
queueId = deviceProfile.getDefaultQueueId();
queueName = deviceProfile.getDefaultQueueName();
}
}
return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueId, ruleChainId);
return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueName, ruleChainId);
}
@Override
@ -382,9 +370,9 @@ class DefaultTbContext implements TbContext {
return entityActionMsg(entity, id, ruleNodeId, action, null, null);
}
public <E, I extends EntityId> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, QueueId queueId, RuleChainId ruleChainId) {
public <E, I extends EntityId> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, String queueName, RuleChainId ruleChainId) {
try {
return TbMsg.newMsg(queueId, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null);
return TbMsg.newMsg(queueName, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null);
} catch (JsonProcessingException | IllegalArgumentException e) {
throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + e);
}

2
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -293,7 +293,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
try {
checkComponentStateActive(msg);
EntityId entityId = msg.getOriginator();
TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, msg.getQueueId(), tenantId, entityId);
TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, msg.getQueueName(), tenantId, entityId);
List<RuleNodeRelation> ruleNodeRelations = nodeRoutes.get(originatorNodeId);
if (ruleNodeRelations == null) { // When unchecked, this will cause NullPointerException when rule node doesn't exist anymore

67
application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java

@ -15,17 +15,21 @@
*/
package org.thingsboard.server.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -35,42 +39,40 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Slf4j
@Component
public class RateLimitProcessingFilter extends GenericFilterBean {
@Value("${server.rest.limits.tenant.enabled:false}")
private boolean perTenantLimitsEnabled;
@Value("${server.rest.limits.tenant.configuration:}")
private String perTenantLimitsConfiguration;
@Value("${server.rest.limits.customer.enabled:false}")
private boolean perCustomerLimitsEnabled;
@Value("${server.rest.limits.customer.configuration:}")
private String perCustomerLimitsConfiguration;
@Autowired
private ThingsboardErrorResponseHandler errorResponseHandler;
private ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>();
private ConcurrentMap<CustomerId, TbRateLimits> perCustomerLimits = new ConcurrentHashMap<>();
@Autowired
@Lazy
private TbTenantProfileCache tenantProfileCache;
private final ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>();
private final ConcurrentMap<CustomerId, TbRateLimits> perCustomerLimits = new ConcurrentHashMap<>();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SecurityUser user = getCurrentUser();
if (user != null && !user.isSystemAdmin()) {
if (perTenantLimitsEnabled) {
TbRateLimits rateLimits = perTenantLimits.computeIfAbsent(user.getTenantId(), id -> new TbRateLimits(perTenantLimitsConfiguration));
if (!rateLimits.tryConsume()) {
errorResponseHandler.handle(new TbRateLimitsException(EntityType.TENANT), (HttpServletResponse) response);
return;
}
var profile = tenantProfileCache.get(user.getTenantId());
if (profile == null) {
log.debug("[{}] Failed to lookup tenant profile", user.getTenantId());
errorResponseHandler.handle(new BadCredentialsException("Failed to lookup tenant profile"), (HttpServletResponse) response);
return;
}
var profileConfiguration = profile.getDefaultProfileConfiguration();
if (!checkRateLimits(user.getTenantId(), profileConfiguration.getTenantServerRestLimitsConfiguration(), perTenantLimits, response)) {
return;
}
if (perCustomerLimitsEnabled && user.isCustomerUser()) {
TbRateLimits rateLimits = perCustomerLimits.computeIfAbsent(user.getCustomerId(), id -> new TbRateLimits(perCustomerLimitsConfiguration));
if (!rateLimits.tryConsume()) {
errorResponseHandler.handle(new TbRateLimitsException(EntityType.CUSTOMER), (HttpServletResponse) response);
if (user.isCustomerUser()) {
if (!checkRateLimits(user.getCustomerId(), profileConfiguration.getCustomerServerRestLimitsConfiguration(), perCustomerLimits, response)) {
return;
}
}
@ -78,6 +80,25 @@ public class RateLimitProcessingFilter extends GenericFilterBean {
chain.doFilter(request, response);
}
private <I extends EntityId> boolean checkRateLimits(I ownerId, String rateLimitConfig, Map<I, TbRateLimits> rateLimitsMap, ServletResponse response) {
if (StringUtils.isNotEmpty(rateLimitConfig)) {
TbRateLimits rateLimits = rateLimitsMap.get(ownerId);
if (rateLimits == null || !rateLimits.getConfiguration().equals(rateLimitConfig)) {
rateLimits = new TbRateLimits(rateLimitConfig);
rateLimitsMap.put(ownerId, rateLimits);
}
if (!rateLimits.tryConsume()) {
errorResponseHandler.handle(new TbRateLimitsException(ownerId.getEntityType()), (HttpServletResponse) response);
return false;
}
} else {
rateLimitsMap.remove(ownerId);
}
return true;
}
protected SecurityUser getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) {

44
application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java

@ -24,22 +24,22 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.thingsboard.server.dao.audit.AuditLogLevelFilter;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -63,7 +63,7 @@ import java.util.List;
@EnableGlobalMethodSecurity(prePostEnabled=true)
@Order(SecurityProperties.BASIC_AUTH_ORDER)
@TbCoreComponent
public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter {
public class ThingsboardSecurityConfiguration {
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization";
@ -161,16 +161,15 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
public AuthenticationManager authenticationManager(ObjectPostProcessor<Object> objectPostProcessor) throws Exception {
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
.postProcess(new DefaultAuthenticationEventPublisher());
var auth = new AuthenticationManagerBuilder(objectPostProcessor);
auth.authenticationEventPublisher(eventPublisher);
auth.authenticationProvider(restAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider);
auth.authenticationProvider(refreshTokenAuthenticationProvider);
return auth.build();
}
@Bean
@ -181,13 +180,20 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
@Autowired
private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorizeHttpRequests) ->
authorizeHttpRequests
.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**")
.permitAll()
);
@Bean
@Order(0)
SecurityFilterChain resources(HttpSecurity http) throws Exception {
http
.requestMatchers((matchers) -> matchers.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**"))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
.requestCache().disable()
.securityContext().disable()
.sessionManagement().disable();
return http.build();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.headers().cacheControl().and().frameOptions().disable()
.and()
.cors()
@ -229,6 +235,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
.successHandler(oauth2AuthenticationSuccessHandler)
.failureHandler(oauth2AuthenticationFailureHandler);
}
return http.build();
}
@Bean
@ -242,5 +249,4 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
return new CorsFilter(source);
}
}
}

156
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -16,16 +16,16 @@
package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.AdminSettings;
@ -34,14 +34,18 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.sync.vc.AutoCommitSettings;
import org.thingsboard.server.common.data.sync.vc.RepositorySettings;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.sync.vc.autocommit.TbAutoCommitSettingsService;
import org.thingsboard.server.service.update.UpdateService;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.*;
@RestController
@TbCoreComponent
@ -60,6 +64,12 @@ public class AdminController extends BaseController {
@Autowired
private SystemSecurityService systemSecurityService;
@Autowired
private EntitiesVersionControlService versionControlService;
@Autowired
private TbAutoCommitSettingsService autoCommitSettingsService;
@Autowired
private UpdateService updateService;
@ -96,6 +106,7 @@ public class AdminController extends BaseController {
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
adminSettings.setTenantId(getTenantId());
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
if (adminSettings.getKey().equals("mail")) {
mailService.updateMailConfiguration();
@ -180,6 +191,137 @@ public class AdminController extends BaseController {
}
}
@ApiOperation(value = "Get repository settings (getRepositorySettings)",
notes = "Get the repository settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/repositorySettings")
@ResponseBody
public RepositorySettings getRepositorySettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
RepositorySettings versionControlSettings = checkNotNull(versionControlService.getVersionControlSettings(getTenantId()));
versionControlSettings.setPassword(null);
versionControlSettings.setPrivateKey(null);
versionControlSettings.setPrivateKeyPassword(null);
return versionControlSettings;
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Check repository settings exists (repositorySettingsExists)",
notes = "Check whether the repository settings exists. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/repositorySettings/exists")
@ResponseBody
public Boolean repositorySettingsExists() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return versionControlService.getVersionControlSettings(getTenantId()) != null;
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Creates or Updates the repository settings (saveRepositorySettings)",
notes = "Creates or Updates the repository settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/repositorySettings")
public DeferredResult<RepositorySettings> saveRepositorySettings(@RequestBody RepositorySettings settings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
ListenableFuture<RepositorySettings> future = versionControlService.saveVersionControlSettings(getTenantId(), settings);
return wrapFuture(Futures.transform(future, savedSettings -> {
savedSettings.setPassword(null);
savedSettings.setPrivateKey(null);
savedSettings.setPrivateKeyPassword(null);
return savedSettings;
}, MoreExecutors.directExecutor()));
}
@ApiOperation(value = "Delete repository settings (deleteRepositorySettings)",
notes = "Deletes the repository settings."
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/repositorySettings", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public DeferredResult<Void> deleteRepositorySettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
return wrapFuture(versionControlService.deleteVersionControlSettings(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Check repository access (checkRepositoryAccess)",
notes = "Attempts to check repository access. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/repositorySettings/checkAccess", method = RequestMethod.POST)
public DeferredResult<Void> checkRepositoryAccess(
@ApiParam(value = "A JSON value representing the Repository Settings.")
@RequestBody RepositorySettings settings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
settings = checkNotNull(settings);
return wrapFuture(versionControlService.checkVersionControlAccess(getTenantId(), settings));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Get auto commit settings (getAutoCommitSettings)",
notes = "Get the auto commit settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/autoCommitSettings")
@ResponseBody
public AutoCommitSettings getAutoCommitSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return checkNotNull(autoCommitSettingsService.get(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Check auto commit settings exists (autoCommitSettingsExists)",
notes = "Check whether the auto commit settings exists. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/autoCommitSettings/exists")
@ResponseBody
public Boolean autoCommitSettingsExists() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return autoCommitSettingsService.get(getTenantId()) != null;
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Creates or Updates the auto commit settings (saveAutoCommitSettings)",
notes = "Creates or Updates the auto commit settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/autoCommitSettings")
public AutoCommitSettings saveAutoCommitSettings(@RequestBody AutoCommitSettings settings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return autoCommitSettingsService.save(getTenantId(), settings);
}
@ApiOperation(value = "Delete auto commit settings (deleteAutoCommitSettings)",
notes = "Deletes the auto commit settings."
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/autoCommitSettings", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteAutoCommitSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
autoCommitSettingsService.delete(getTenantId());
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Check for new Platform Releases (checkUpdates)",
notes = "Check notifications about new platform releases. "
+ SYSTEM_AUTHORITY_PARAGRAPH)

24
application/src/main/java/org/thingsboard/server/controller/AlarmController.java

@ -126,13 +126,15 @@ public class AlarmController extends BaseController {
"\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " +
"For example, if the user or system component create the alarm with the type 'HighTemperature' for device 'Device A' the new active alarm is created. " +
"If the user tries to create 'HighTemperature' alarm for the same device again, the previous alarm will be updated (the 'end_ts' will be set to current timestamp). " +
"If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
"If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Alarm entity. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
, produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm", method = RequestMethod.POST)
@ResponseBody
public Alarm saveAlarm(@ApiParam(value = "A JSON value representing the alarm.") @RequestBody Alarm alarm) throws ThingsboardException {
alarm.setTenantId(getCurrentUser().getTenantId());
alarm.setTenantId(getTenantId());
checkEntity(alarm.getId(), alarm, Resource.ALARM);
return tbAlarmService.save(alarm, getCurrentUser());
}
@ -144,13 +146,9 @@ public class AlarmController extends BaseController {
@ResponseBody
public Boolean deleteAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
try {
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
return tbAlarmService.delete(alarm, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.DELETE);
return tbAlarmService.delete(alarm, getCurrentUser());
}
@ApiOperation(value = "Acknowledge Alarm (ackAlarm)",
@ -160,11 +158,11 @@ public class AlarmController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void ackAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
public void ackAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
tbAlarmService.ack(alarm, getCurrentUser());
tbAlarmService.ack(alarm, getCurrentUser()).get();
}
@ApiOperation(value = "Clear Alarm (clearAlarm)",
@ -174,11 +172,11 @@ public class AlarmController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void clearAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
public void clearAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
tbAlarmService.clear(alarm, getCurrentUser());
tbAlarmService.clear(alarm, getCurrentUser()).get();
}
@ApiOperation(value = "Get Alarms (getAlarms)",

24
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -51,9 +51,9 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.asset.AssetBulkImportService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.importing.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -139,15 +139,17 @@ public class AssetController extends BaseController {
notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as " + UUID_WIKI_LINK +
"The newly created Asset id will be present in the response. " +
"Specify existing Asset id to update the asset. " +
"Referencing non-existing Asset Id will cause 'Not Found' error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE)
"Referencing non-existing Asset Id will cause 'Not Found' error. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Asset entity. "
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset", method = RequestMethod.POST)
@ResponseBody
public Asset saveAsset(@ApiParam(value = "A JSON value representing the asset.") @RequestBody Asset asset) throws ThingsboardException {
public Asset saveAsset(@ApiParam(value = "A JSON value representing the asset.") @RequestBody Asset asset) throws Exception {
if (TB_SERVICE_QUEUE.equals(asset.getType())) {
throw new ThingsboardException("Unable to save asset with type " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
asset.setTenantId(getCurrentUser().getTenantId());
asset.setTenantId(getTenantId());
checkEntity(asset.getId(), asset, Resource.ASSET);
return tbAssetService.save(asset, getCurrentUser());
}
@ -157,15 +159,11 @@ public class AssetController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteAsset(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
public void deleteAsset(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws Exception {
checkParameter(ASSET_ID, strAssetId);
try {
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId, Operation.DELETE);
tbAssetService.delete(asset, getCurrentUser()).get();
} catch (Exception e) {
throw handleException(e);
}
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId, Operation.DELETE);
tbAssetService.delete(asset, getCurrentUser()).get();
}
@ApiOperation(value = "Assign asset to customer (assignAssetToCustomer)",

42
application/src/main/java/org/thingsboard/server/controller/AutoCommitController.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import java.util.UUID;
public class AutoCommitController extends BaseController {
@Autowired
private EntitiesVersionControlService vcService;
protected ListenableFuture<UUID> autoCommit(User user, EntityId entityId) throws Exception {
if (vcService != null) {
return vcService.autoCommit(user, entityId);
} else {
// We do not support auto-commit for rule engine
return Futures.immediateFailedFuture(new RuntimeException("Operation not supported!"));
}
}
}

119
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -15,9 +15,12 @@
*/
package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
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.MoreExecutors;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -29,6 +32,8 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
@ -39,7 +44,6 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
@ -53,7 +57,6 @@ import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetInfo;
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;
@ -88,7 +91,6 @@ import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.rpc.Rpc;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType;
@ -126,10 +128,10 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.resource.TbResourceService;
@ -138,6 +140,7 @@ import org.thingsboard.server.service.security.permission.AccessControlService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.state.DeviceStateService;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.telemetry.AlarmSubscriptionService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
@ -276,11 +279,14 @@ public abstract class BaseController {
protected EdgeRpcService edgeGrpcService;
@Autowired
protected EntityActionService entityActionService;
protected TbNotificationEntityService notificationEntityService;
@Autowired
protected QueueService queueService;
@Autowired
protected EntitiesVersionControlService vcService;
@Value("${server.log_controller_error_stack_trace}")
@Getter
private boolean logControllerErrorStackTrace;
@ -341,6 +347,8 @@ public abstract class BaseController {
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else if (exception instanceof MessagingException) {
return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL);
} else if (exception instanceof AsyncRequestTimeoutException) {
return new ThingsboardException("Request timeout", ThingsboardErrorCode.GENERAL);
} else {
return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL);
}
@ -882,95 +890,20 @@ public abstract class BaseController {
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
}
protected <E extends HasName, I extends EntityId> void logEntityAction(I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException {
logEntityAction(getCurrentUser(), entityId, entity, customerId, actionType, e, additionalInfo);
}
protected <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException {
entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo);
}
public static Exception toException(Throwable error) {
return error != null ? (Exception.class.isInstance(error) ? (Exception) error : new Exception(error)) : null;
}
protected <E extends HasName> String entityToStr(E entity) {
try {
return json.writeValueAsString(json.valueToTree(entity));
} catch (JsonProcessingException e) {
log.warn("[{}] Failed to convert entity to string!", entity, e);
}
return null;
}
protected void sendRelationNotificationMsg(TenantId tenantId, EntityRelation relation, EdgeEventActionType action) {
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) {
sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, action);
}
} catch (Exception e) {
log.warn("Failed to push relation to core: {}", relation, e);
}
}
protected void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds) {
sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null);
}
protected void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, String body) {
if (edgeIds != null && !edgeIds.isEmpty()) {
for (EdgeId edgeId : edgeIds) {
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED);
}
}
}
protected void sendAlarmDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, Alarm alarm) {
try {
sendDeleteNotificationMsg(tenantId, entityId, edgeIds, json.writeValueAsString(alarm));
} catch (Exception e) {
log.warn("Failed to push delete alarm msg to core: {}", alarm, e);
}
}
protected void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) {
try {
sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action);
} catch (Exception e) {
log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e);
}
}
protected void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) {
sendNotificationMsgToEdgeService(tenantId, null, entityId, null, null, action);
sendNotificationMsgToEdge(tenantId, null, entityId, null, null, action);
}
protected void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) {
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, action);
sendNotificationMsgToEdge(tenantId, edgeId, entityId, null, null, action);
}
private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action);
}
protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {
if (!edgesEnabled) {
return null;
}
if (EntityType.EDGE.equals(entityId.getEntityType())) {
return Collections.singletonList(new EdgeId(entityId.getId()));
}
PageDataIterableByTenantIdEntityId<EdgeId> relatedEdgeIdsIterator =
new PageDataIterableByTenantIdEntityId<>(edgeService::findRelatedEdgeIdsByEntityId, tenantId, entityId, DEFAULT_PAGE_SIZE);
List<EdgeId> result = new ArrayList<>();
for (EdgeId edgeId : relatedEdgeIdsIterator) {
result.add(edgeId);
}
return result;
private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, type, action);
}
protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException {
@ -989,4 +922,20 @@ public abstract class BaseController {
return MediaType.APPLICATION_OCTET_STREAM;
}
}
protected <T> DeferredResult<T> wrapFuture(ListenableFuture<T> future) {
final DeferredResult<T> deferredResult = new DeferredResult<>();
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(T result) {
deferredResult.setResult(result);
}
@Override
public void onFailure(Throwable t) {
deferredResult.setErrorResult(t);
}
}, MoreExecutors.directExecutor());
return deferredResult;
}
}

11
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -30,7 +30,7 @@ public class ControllerConstants {
protected static final String PAGE_DATA_PARAMETERS = "You can specify parameters to filter the results. " +
"The result is wrapped with PageData object that allows you to iterate over result set using pagination. " +
"See the 'Model' tab of the Response Class for more details. ";
protected static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the dashboard id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String ENTITY_VIEW_ID_PARAM_DESCRIPTION = "A string value representing the entity view id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
@ -49,6 +49,7 @@ public class ControllerConstants {
protected static final String RULE_NODE_ID_PARAM_DESCRIPTION = "A string value representing the rule node id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String VC_REQUEST_ID_PARAM_DESCRIPTION = "A string value representing the version control request id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority.";
protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority.";
@ -111,6 +112,10 @@ public class ControllerConstants {
protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. ";
protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)";
protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR";
protected static final String QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the queue name.";
protected static final String QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, topic";
protected static final String QUEUE_ID_PARAM_DESCRIPTION = "A string value representing the queue id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String QUEUE_NAME_PARAM_DESCRIPTION = "A string value representing the queue id. For example, 'Main'";
protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. ";
protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. ";
protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128";
@ -135,6 +140,10 @@ public class ControllerConstants {
protected static final String EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION = "Assignment works in async way - first, notification event pushed to edge service queue on platform. ";
protected static final String EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION = "(Edge will receive this instantly, if it's currently connected, or once it's going to be connected to platform). ";
protected static final String ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the entity version name.";
protected static final String VERSION_ID_PARAM_DESCRIPTION = "Version id, for example fd82625bdd7d6131cf8027b44ee967012ecaf990. Represents commit hash.";
protected static final String BRANCH_PARAM_DESCRIPTION = "The name of the working branch, for example 'master'";
protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n";
protected static final String MARKDOWN_CODE_BLOCK_END = "\n```";
protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START +

12
application/src/main/java/org/thingsboard/server/controller/CustomerController.java

@ -138,11 +138,13 @@ public class CustomerController extends BaseController {
notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as " + UUID_WIKI_LINK +
"The newly created Customer Id will be present in the response. " +
"Specify existing Customer Id to update the Customer. " +
"Referencing non-existing Customer Id will cause 'Not Found' error." + TENANT_AUTHORITY_PARAGRAPH)
"Referencing non-existing Customer Id will cause 'Not Found' error." +
"Remove 'id', 'tenantId' from the request body example (below) to create new Customer entity. " +
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer", method = RequestMethod.POST)
@ResponseBody
public Customer saveCustomer(@ApiParam(value = "A JSON value representing the customer.") @RequestBody Customer customer) throws ThingsboardException {
public Customer saveCustomer(@ApiParam(value = "A JSON value representing the customer.") @RequestBody Customer customer) throws Exception {
customer.setTenantId(getTenantId());
checkEntity(customer.getId(), customer, Resource.CUSTOMER);
return tbCustomerService.save(customer, getCurrentUser());
@ -160,11 +162,7 @@ public class CustomerController extends BaseController {
checkParameter(CUSTOMER_ID, strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.DELETE);
try {
tbCustomerService.delete(customer, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
tbCustomerService.delete(customer, getCurrentUser());
}
@ApiOperation(value = "Get Tenant Customers (getCustomers)",

26
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -172,6 +172,7 @@ public class DashboardController extends BaseController {
"The newly created Dashboard id will be present in the response. " +
"Specify existing Dashboard id to update the dashboard. " +
"Referencing non-existing dashboard Id will cause 'Not Found' error. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Dashboard entity. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
@ -180,7 +181,7 @@ public class DashboardController extends BaseController {
@ResponseBody
public Dashboard saveDashboard(
@ApiParam(value = "A JSON value representing the dashboard.")
@RequestBody Dashboard dashboard) throws ThingsboardException {
@RequestBody Dashboard dashboard) throws Exception {
dashboard.setTenantId(getTenantId());
checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD);
return tbDashboardService.save(dashboard, getCurrentUser());
@ -219,8 +220,8 @@ public class DashboardController extends BaseController {
Customer customer = checkCustomerId(customerId, Operation.READ);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
return tbDashboardService.assignDashboardToCustomer(dashboardId, customer, getCurrentUser());
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
return tbDashboardService.assignDashboardToCustomer(dashboard, customer, getCurrentUser());
}
@ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)",
@ -261,7 +262,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
Set<CustomerId> customerIds = customerIdFromStr(strCustomerIds, dashboard);
Set<CustomerId> customerIds = customerIdFromStr(strCustomerIds);
return tbDashboardService.updateDashboardCustomers(dashboard, customerIds, getCurrentUser());
}
@ -281,7 +282,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
Set<CustomerId> customerIds = customerIdFromStr(strCustomerIds, dashboard);
Set<CustomerId> customerIds = customerIdFromStr(strCustomerIds);
return tbDashboardService.addDashboardCustomers(dashboard, customerIds, getCurrentUser());
}
@ -301,7 +302,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER);
Set<CustomerId> customerIds = customerIdFromStr(strCustomerIds, dashboard);
Set<CustomerId> customerIds = customerIdFromStr(strCustomerIds);
return tbDashboardService.removeDashboardCustomers(dashboard, customerIds, getCurrentUser());
}
@ -321,8 +322,8 @@ public class DashboardController extends BaseController {
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
return tbDashboardService.assignDashboardToPublicCustomer(dashboardId, getCurrentUser());
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
return tbDashboardService.assignDashboardToPublicCustomer(dashboard, getCurrentUser());
}
@ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)",
@ -631,7 +632,7 @@ public class DashboardController extends BaseController {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId, Operation.READ);
return tbDashboardService.asignDashboardToEdge(dashboardId, edge, getCurrentUser());
return tbDashboardService.asignDashboardToEdge(getTenantId(), dashboardId, edge, getCurrentUser());
}
@ApiOperation(value = "Unassign dashboard from edge (unassignDashboardFromEdge)",
@ -704,14 +705,11 @@ public class DashboardController extends BaseController {
}
}
private Set<CustomerId> customerIdFromStr(String [] strCustomerIds, Dashboard dashboard) {
private Set<CustomerId> customerIdFromStr(String[] strCustomerIds) {
Set<CustomerId> customerIds = new HashSet<>();
if (strCustomerIds != null) {
for (String strCustomerId : strCustomerIds) {
CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId));
if (dashboard.isAssignedToCustomer(customerId)) {
customerIds.add(customerId);
}
customerIds.add(new CustomerId(UUID.fromString(strCustomerId)));
}
}
return customerIds;

85
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -66,9 +66,9 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.importing.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -158,14 +158,15 @@ public class DeviceController extends BaseController {
"The newly created device id will be present in the response. " +
"Specify existing Device id to update the device. " +
"Referencing non-existing device Id will cause 'Not Found' error." +
"\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes."
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
"\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes." +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device", method = RequestMethod.POST)
@ResponseBody
public Device saveDevice(@ApiParam(value = "A JSON value representing the device.") @RequestBody Device device,
@ApiParam(value = "Optional value of the device credentials to be used during device creation. " +
"If omitted, access token will be auto-generated.") @RequestParam(name = "accessToken", required = false) String accessToken) throws ThingsboardException {
"If omitted, access token will be auto-generated.") @RequestParam(name = "accessToken", required = false) String accessToken) throws Exception {
device.setTenantId(getCurrentUser().getTenantId());
Device oldDevice = null;
if (device.getId() != null) {
@ -173,7 +174,7 @@ public class DeviceController extends BaseController {
} else {
checkEntity(null, device, Resource.DEVICE);
}
return tbDeviceService.save(getTenantId(), device, oldDevice, accessToken, getCurrentUser());
return tbDeviceService.save(device, oldDevice, accessToken, getCurrentUser());
}
@ApiOperation(value = "Create Device (saveDevice) with credentials ",
@ -181,6 +182,7 @@ public class DeviceController extends BaseController {
"Requires to provide the Device Credentials object as well. Useful to create device and credentials in one request. " +
"You may find the example of LwM2M device and RPK credentials below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST)
@ -191,25 +193,20 @@ public class DeviceController extends BaseController {
DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials());
device.setTenantId(getCurrentUser().getTenantId());
checkEntity(device.getId(), device, Resource.DEVICE);
return tbDeviceService.saveDeviceWithCredentials(getTenantId(), device, credentials, getCurrentUser());
return tbDeviceService.saveDeviceWithCredentials(device, credentials, getCurrentUser());
}
@ApiOperation(value = "Delete device (deleteDevice)",
notes = "Deletes the device, it's credentials and all the relations (from and to the device). Referencing non-existing device Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteDevice(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
@PathVariable(DEVICE_ID) String strDeviceId) throws Exception {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId, Operation.DELETE);
try {
tbDeviceService.delete(device, getCurrentUser()).get();
} catch (Exception e) {
throw handleException(e);
}
tbDeviceService.delete(device, getCurrentUser()).get();
}
@ApiOperation(value = "Assign device to customer (assignDeviceToCustomer)",
@ -238,19 +235,15 @@ public class DeviceController extends BaseController {
public Device unassignDeviceFromCustomer(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
try {
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_CUSTOMER);
if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
throw new IncorrectParameterException("Device isn't assigned to any customer!");
}
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_CUSTOMER);
if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
throw new IncorrectParameterException("Device isn't assigned to any customer!");
}
Customer customer = checkCustomerId(device.getCustomerId(), Operation.READ);
Customer customer = checkCustomerId(device.getCustomerId(), Operation.READ);
return tbDeviceService.unassignDeviceFromCustomer(device, customer, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
return tbDeviceService.unassignDeviceFromCustomer(device, customer, getCurrentUser());
}
@ApiOperation(value = "Make device publicly available (assignDeviceToPublicCustomer)",
@ -566,7 +559,7 @@ public class DeviceController extends BaseController {
ListenableFuture<ClaimResult> future = tbDeviceService.claimDevice(tenantId, device, customerId, secretKey, user);
Futures.addCallback(future, new FutureCallback<ClaimResult>() {
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable ClaimResult result) {
HttpStatus status;
@ -600,32 +593,28 @@ public class DeviceController extends BaseController {
public DeferredResult<ResponseEntity> reClaimDevice(@ApiParam(value = "Unique name of the device which is going to be reclaimed")
@PathVariable(DEVICE_NAME) String deviceName) throws ThingsboardException {
checkParameter(DEVICE_NAME, deviceName);
try {
final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
Device device = checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES,
device.getId(), device);
Device device = checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES,
device.getId(), device);
ListenableFuture<ReclaimResult> result = tbDeviceService.reclaimDevice(tenantId, device, user);
Futures.addCallback(result, new FutureCallback<>() {
@Override
public void onSuccess(ReclaimResult reclaimResult) {
deferredResult.setResult(new ResponseEntity(HttpStatus.OK));
}
ListenableFuture<ReclaimResult> result = tbDeviceService.reclaimDevice(tenantId, device, user);
Futures.addCallback(result, new FutureCallback<>() {
@Override
public void onSuccess(ReclaimResult reclaimResult) {
deferredResult.setResult(new ResponseEntity(HttpStatus.OK));
}
@Override
public void onFailure(Throwable t) {
deferredResult.setErrorResult(t);
}
}, MoreExecutors.directExecutor());
return deferredResult;
} catch (Exception e) {
throw handleException(e);
}
@Override
public void onFailure(Throwable t) {
deferredResult.setErrorResult(t);
}
}, MoreExecutors.directExecutor());
return deferredResult;
}
private String getSecretKey(ClaimRequest claimRequest) {

11
application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java

@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.deviceProfile.TbDeviceProfileService;
import org.thingsboard.server.service.entitiy.device.profile.TbDeviceProfileService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -71,7 +71,7 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@Slf4j
public class DeviceProfileController extends BaseController {
private final TbDeviceProfileService tbDeviceProfileService;
private final TbDeviceProfileService tbDeviceProfileService;
@Autowired
private TimeseriesService timeseriesService;
@ -108,7 +108,7 @@ public class DeviceProfileController extends BaseController {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return checkNotNull(deviceProfileService.findDeviceProfileInfoById(getTenantId(), deviceProfileId));
return new DeviceProfileInfo(checkDeviceProfileId(deviceProfileId, Operation.READ));
} catch (Exception e) {
throw handleException(e);
}
@ -191,6 +191,7 @@ public class DeviceProfileController extends BaseController {
"Specify existing device profile id to update the device profile. " +
"Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE +
"Device profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + DEVICE_PROFILE_DATA +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device Profile entity. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json",
consumes = "application/json")
@ -199,7 +200,7 @@ public class DeviceProfileController extends BaseController {
@ResponseBody
public DeviceProfile saveDeviceProfile(
@ApiParam(value = "A JSON value representing the device profile.")
@RequestBody DeviceProfile deviceProfile) throws ThingsboardException {
@RequestBody DeviceProfile deviceProfile) throws Exception {
deviceProfile.setTenantId(getTenantId());
checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
return tbDeviceProfileService.save(deviceProfile, getCurrentUser());
@ -219,7 +220,7 @@ public class DeviceProfileController extends BaseController {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE);
tbDeviceProfileService.delete(deviceProfile, getCurrentUser());
}
}
@ApiOperation(value = "Make Device Profile Default (setDefaultDeviceProfile)",
notes = "Marks device profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH,

18
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.edge.Edge;
@ -52,8 +53,8 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.importing.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -140,15 +141,16 @@ public class EdgeController extends BaseController {
"The newly created edge id will be present in the response. " +
"Specify existing Edge id to update the edge. " +
"Referencing non-existing Edge Id will cause 'Not Found' error." +
"\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes."
+ TENANT_AUTHORITY_PARAGRAPH,
"\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes." +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Edge entity. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST)
@ResponseBody
public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true)
@RequestBody Edge edge) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
@RequestBody Edge edge) throws Exception {
TenantId tenantId = getTenantId();
edge.setTenantId(tenantId);
boolean created = edge.getId() == null;
@ -351,7 +353,7 @@ public class EdgeController extends BaseController {
public Edge setEdgeRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException {
@PathVariable("ruleChainId") String strRuleChainId) throws Exception {
checkParameter(EDGE_ID, strEdgeId);
checkParameter("ruleChainId", strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -557,7 +559,7 @@ public class EdgeController extends BaseController {
edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId);
return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId, TbRuleChainInputNode.class.getName());
} catch (Exception e) {
throw handleException(e);
}

519
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -0,0 +1,519 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
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.sync.vc.BranchInfo;
import org.thingsboard.server.common.data.sync.vc.EntityDataDiff;
import org.thingsboard.server.common.data.sync.vc.EntityDataInfo;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.BRANCH_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.VC_REQUEST_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.VERSION_ID_PARAM_DESCRIPTION;
@RestController
@TbCoreComponent
@RequestMapping("/api/entities/vc")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequiredArgsConstructor
public class EntitiesVersionControlController extends BaseController {
private final EntitiesVersionControlService versionControlService;
@ApiOperation(value = "Save entities version (saveEntitiesVersion)", notes = "" +
"Creates a new version of entities (or a single entity) by request.\n" +
"Supported entity types: CUSTOMER, ASSET, RULE_CHAIN, DASHBOARD, DEVICE_PROFILE, DEVICE, ENTITY_VIEW, WIDGETS_BUNDLE." + NEW_LINE +
"There are two available types of request: `SINGLE_ENTITY` and `COMPLEX`. " +
"Each of them contains version name (`versionName`) and name of a branch (`branch`) to create version (commit) in. " +
"If specified branch does not exists in a remote repo, then new empty branch will be created. " +
"Request of the `SINGLE_ENTITY` type has id of an entity (`entityId`) and additional configuration (`config`) " +
"which has following options: \n" +
"- `saveRelations` - whether to add inbound and outbound relations of type COMMON to created entity version;\n" +
"- `saveAttributes` - to save attributes of server scope (and also shared scope for devices);\n" +
"- `saveCredentials` - when saving a version of a device, to add its credentials to the version." + NEW_LINE +
"An example of a `SINGLE_ENTITY` version create request:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"type\": \"SINGLE_ENTITY\",\n" +
"\n" +
" \"versionName\": \"Version 1.0\",\n" +
" \"branch\": \"dev\",\n" +
"\n" +
" \"entityId\": {\n" +
" \"entityType\": \"DEVICE\",\n" +
" \"id\": \"b79448e0-d4f4-11ec-847b-0f432358ab48\"\n" +
" },\n" +
" \"config\": {\n" +
" \"saveRelations\": true,\n" +
" \"saveAttributes\": true,\n" +
" \"saveCredentials\": false\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END + NEW_LINE +
"Second request type (`COMPLEX`), additionally to `branch` and `versionName`, contains following properties:\n" +
"- `entityTypes` - a structure with entity types to export and configuration for each entity type; " +
" this configuration has all the options available for `SINGLE_ENTITY` and additionally has these ones: \n" +
" - `allEntities` and `entityIds` - if you want to save the version of all entities of the entity type " +
" then set `allEntities` param to true, otherwise set it to false and specify the list of specific entities (`entityIds`);\n" +
" - `syncStrategy` - synchronization strategy to use for this entity type: when set to `OVERWRITE` " +
" then the list of remote entities of this type will be overwritten by newly added entities. If set to " +
" `MERGE` - existing remote entities of this entity type will not be removed, new entities will just " +
" be added on top (or existing remote entities will be updated).\n" +
"- `syncStrategy` - default synchronization strategy to use when it is not specified for an entity type." + NEW_LINE +
"Example for this type of request:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"type\": \"COMPLEX\",\n" +
"\n" +
" \"versionName\": \"Devices and profiles: release 2\",\n" +
" \"branch\": \"master\",\n" +
"\n" +
" \"syncStrategy\": \"OVERWRITE\",\n" +
" \"entityTypes\": {\n" +
" \"DEVICE\": {\n" +
" \"syncStrategy\": null,\n" +
" \"allEntities\": true,\n" +
" \"saveRelations\": true,\n" +
" \"saveAttributes\": true,\n" +
" \"saveCredentials\": true\n" +
" },\n" +
" \"DEVICE_PROFILE\": {\n" +
" \"syncStrategy\": \"MERGE\",\n" +
" \"allEntities\": false,\n" +
" \"entityIds\": [\n" +
" \"b79448e0-d4f4-11ec-847b-0f432358ab48\"\n" +
" ],\n" +
" \"saveRelations\": true\n" +
" }\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END + NEW_LINE +
"Response wil contain generated request UUID, that can be then used to retrieve " +
"status of operation via `getVersionCreateRequestStatus`.\n" +
TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/version")
public DeferredResult<UUID> saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws Exception {
SecurityUser user = getCurrentUser();
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return wrapFuture(versionControlService.saveEntitiesVersion(user, request));
}
@ApiOperation(value = "Get version create request status (getVersionCreateRequestStatus)", notes = "" +
"Returns the status of previously made version create request. " + NEW_LINE +
"This status contains following properties:\n" +
"- `done` - whether request processing is finished;\n" +
"- `version` - created version info: timestamp, version id (commit hash), commit name and commit author;\n" +
"- `added` - count of items that were created in the remote repo;\n" +
"- `modified` - modified items count;\n" +
"- `removed` - removed items count;\n" +
"- `error` - error message, if an error occurred while handling the request." + NEW_LINE +
"An example of successful status:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"done\": true,\n" +
" \"added\": 10,\n" +
" \"modified\": 2,\n" +
" \"removed\": 5,\n" +
" \"version\": {\n" +
" \"timestamp\": 1655198528000,\n" +
" \"id\":\"8a834dd389ed80e0759ba8ee338b3f1fd160a114\",\n" +
" \"name\": \"My devices v2.0\",\n" +
" \"author\": \"John Doe\"\n" +
" },\n" +
" \"error\": null\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{requestId}/status")
public VersionCreationResult getVersionCreateRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID requestId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.getVersionCreateStatus(getCurrentUser(), requestId);
}
@ApiOperation(value = "List entity versions (listEntityVersions)", notes = "" +
"Returns list of versions for a specific entity in a concrete branch. \n" +
"You need to specify external id of an entity to list versions for. This is `externalId` property of an entity, " +
"or otherwise if not set - simply id of this entity. \n" +
"If specified branch does not exist - empty page data will be returned. " + NEW_LINE +
"Each version info item has timestamp, id, name and author. Version id can then be used to restore the version. " +
PAGE_DATA_PARAMETERS + NEW_LINE +
"Response example: \n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"data\": [\n" +
" {\n" +
" \"timestamp\": 1655198593000,\n" +
" \"id\": \"fd82625bdd7d6131cf8027b44ee967012ecaf990\",\n" +
" \"name\": \"Devices and assets - v2.0\",\n" +
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1655198528000,\n" +
" \"id\": \"682adcffa9c8a2f863af6f00c4850323acbd4219\",\n" +
" \"name\": \"Update my device\",\n" +
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1655198280000,\n" +
" \"id\": \"d2a6087c2b30e18cc55e7cdda345a8d0dfb959a4\",\n" +
" \"name\": \"Devices and assets - v1.0\",\n" +
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" +
" }\n" +
" ],\n" +
" \"totalPages\": 1,\n" +
" \"totalElements\": 3,\n" +
" \"hasNext\": false\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{entityType}/{externalEntityUuid}", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listEntityVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = "A string value representing external entity id. This is `externalId` property of an entity, or otherwise if not set - simply id of this entity.")
@PathVariable UUID externalEntityUuid,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return wrapFuture(versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId, pageLink));
}
@ApiOperation(value = "List entity type versions (listEntityTypeVersions)", notes = "" +
"Returns list of versions of an entity type in a branch. This is a collected list of versions that were created " +
"for entities of this type in a remote branch. \n" +
"If specified branch does not exist - empty page data will be returned. " +
"The response structure is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{entityType}", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listEntityTypeVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return wrapFuture(versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType, pageLink));
}
@ApiOperation(value = "List all versions (listVersions)", notes = "" +
"Lists all available versions in a branch for all entity types. \n" +
"If specified branch does not exist - empty page data will be returned. " +
"The response format is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listVersions(@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return wrapFuture(versionControlService.listVersions(getTenantId(), branch, pageLink));
}
@ApiOperation(value = "List entities at version (listEntitiesAtVersion)", notes = "" +
"Returns a list of remote entities of a specific entity type that are available at a concrete version. \n" +
"Each entity item in the result has `externalId` property. " +
"Entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{entityType}/{versionId}")
public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), versionId, entityType));
}
@ApiOperation(value = "List all entities at version (listAllEntitiesAtVersion)", notes = "" +
"Returns a list of all remote entities available in a specific version. " +
"Response type is the same as for listAllEntitiesAtVersion API method. \n" +
"Returned entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{versionId}")
public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), versionId));
}
@ApiOperation(value = "Get entity data info (getEntityDataInfo)", notes = "" +
"Retrieves short info about the remote entity by external id at a concrete version. \n" +
"Returned entity data info contains following properties: " +
"`hasRelations` (whether stored entity data contains relations), `hasAttributes` (contains attributes) and " +
"`hasCredentials` (whether stored device data has credentials)." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}")
public DeferredResult<EntityDataInfo> getEntityDataInfo(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = "A string value representing external entity id", required = true)
@PathVariable UUID externalEntityUuid) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
return wrapFuture(versionControlService.getEntityDataInfo(getCurrentUser(), entityId, versionId));
}
@ApiOperation(value = "Compare entity data to version (compareEntityDataToVersion)", notes = "" +
"Returns an object with current entity data and the one at a specific version. " +
"Entity data structure is the same as stored in a repository. " +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"versionId"})
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID internalEntityUuid,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@RequestParam String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid);
return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), entityId, versionId));
}
@ApiOperation(value = "Load entities version (loadEntitiesVersion)", notes = "" +
"Loads specific version of remote entities (or single entity) by request. " +
"Supported entity types: CUSTOMER, ASSET, RULE_CHAIN, DASHBOARD, DEVICE_PROFILE, DEVICE, ENTITY_VIEW, WIDGETS_BUNDLE." + NEW_LINE +
"There are multiple types of request. Each of them requires branch name (`branch`) and version id (`versionId`). " +
"Request of type `SINGLE_ENTITY` is needed to restore a concrete version of a specific entity. It contains " +
"id of a remote entity (`externalEntityId`) and additional configuration (`config`):\n" +
"- `loadRelations` - to update relations list (in case `saveRelations` option was enabled during version creation);\n" +
"- `loadAttributes` - to load entity attributes (if `saveAttributes` config option was enabled);\n" +
"- `loadCredentials` - to update device credentials (if `saveCredentials` option was enabled during version creation)." + NEW_LINE +
"An example of such request:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"type\": \"SINGLE_ENTITY\",\n" +
" \n" +
" \"branch\": \"dev\",\n" +
" \"versionId\": \"b3c28d722d328324c7c15b0b30047b0c40011cf7\",\n" +
" \n" +
" \"externalEntityId\": {\n" +
" \"entityType\": \"DEVICE\",\n" +
" \"id\": \"b7944123-d4f4-11ec-847b-0f432358ab48\"\n" +
" },\n" +
" \"config\": {\n" +
" \"loadRelations\": false,\n" +
" \"loadAttributes\": true,\n" +
" \"loadCredentials\": true\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END + NEW_LINE +
"Another request type (`ENTITY_TYPE`) is needed to load specific version of the whole entity types. " +
"It contains a structure with entity types to load and configs for each entity type (`entityTypes`). " +
"For each specified entity type, the method will load all remote entities of this type that are present " +
"at the version. A config for each entity type contains the same options as in `SINGLE_ENTITY` request type, and " +
"additionally contains following options:\n" +
"- `removeOtherEntities` - to remove local entities that are not present on the remote - basically to " +
" overwrite local entity type with the remote one;\n" +
"- `findExistingEntityByName` - when you are loading some remote entities that are not yet present at this tenant, " +
" try to find existing entity by name and update it rather than create new." + NEW_LINE +
"Here is an example of the request to completely restore version of the whole device entity type:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"type\": \"ENTITY_TYPE\",\n" +
"\n" +
" \"branch\": \"dev\",\n" +
" \"versionId\": \"b3c28d722d328324c7c15b0b30047b0c40011cf7\",\n" +
"\n" +
" \"entityTypes\": {\n" +
" \"DEVICE\": {\n" +
" \"removeOtherEntities\": true,\n" +
" \"findExistingEntityByName\": false,\n" +
" \"loadRelations\": true,\n" +
" \"loadAttributes\": true,\n" +
" \"loadCredentials\": true\n" +
" }\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END + NEW_LINE +
"The response will contain generated request UUID that is to be used to check the status of operation " +
"via `getVersionLoadRequestStatus`." +
TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/entity")
public UUID loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws Exception {
SecurityUser user = getCurrentUser();
accessControlService.checkPermission(user, Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.loadEntitiesVersion(user, request);
}
@ApiOperation(value = "Get version load request status (getVersionLoadRequestStatus)", notes = "" +
"Returns the status of previously made version load request. " +
"The structure contains following parameters:\n" +
"- `done` - if the request was successfully processed;\n" +
"- `result` - a list of load results for each entity type:\n" +
" - `created` - created entities count;\n" +
" - `updated` - updated entities count;\n" +
" - `deleted` - removed entities count.\n" +
"- `error` - if an error occurred during processing, error info:\n" +
" - `type` - error type;\n" +
" - `source` - an external id of remote entity;\n" +
" - `target` - if failed to find referenced entity by external id - this external id;\n" +
" - `message` - error message." + NEW_LINE +
"An example of successfully processed request status:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"done\": true,\n" +
" \"result\": [\n" +
" {\n" +
" \"entityType\": \"DEVICE\",\n" +
" \"created\": 10,\n" +
" \"updated\": 5,\n" +
" \"deleted\": 5\n" +
" },\n" +
" {\n" +
" \"entityType\": \"ASSET\",\n" +
" \"created\": 4,\n" +
" \"updated\": 0,\n" +
" \"deleted\": 8\n" +
" }\n" +
" ]\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH
)
@GetMapping(value = "/entity/{requestId}/status")
public VersionLoadResult getVersionLoadRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID requestId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.getVersionLoadStatus(getCurrentUser(), requestId);
}
@ApiOperation(value = "List branches (listBranches)", notes = "" +
"Lists branches available in the remote repository. \n\n" +
"Response example: \n" +
MARKDOWN_CODE_BLOCK_START +
"[\n" +
" {\n" +
" \"name\": \"master\",\n" +
" \"default\": true\n" +
" },\n" +
" {\n" +
" \"name\": \"dev\",\n" +
" \"default\": false\n" +
" },\n" +
" {\n" +
" \"name\": \"dev-2\",\n" +
" \"default\": false\n" +
" }\n" +
"]" +
MARKDOWN_CODE_BLOCK_END)
@GetMapping("/branches")
public DeferredResult<List<BranchInfo>> listBranches() throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
final TenantId tenantId = getTenantId();
ListenableFuture<List<BranchInfo>> branches = versionControlService.listBranches(tenantId);
return wrapFuture(Futures.transform(branches, remoteBranches -> {
List<BranchInfo> infos = new ArrayList<>();
BranchInfo defaultBranch;
String defaultBranchName = versionControlService.getVersionControlSettings(tenantId).getDefaultBranch();
if (StringUtils.isNotEmpty(defaultBranchName)) {
defaultBranch = new BranchInfo(defaultBranchName, true);
} else {
defaultBranch = remoteBranches.stream().filter(BranchInfo::isDefault).findFirst().orElse(null);
}
if (defaultBranch != null) {
infos.add(defaultBranch);
}
infos.addAll(remoteBranches.stream().filter(b -> !b.equals(defaultBranch))
.map(b -> new BranchInfo(b.getName(), false)).collect(Collectors.toList()));
return infos;
}, MoreExecutors.directExecutor()));
}
}

27
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java

@ -36,7 +36,8 @@ import org.thingsboard.server.common.data.relation.EntityRelationInfo;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.entityRelation.TbEntityRelationService;
import org.thingsboard.server.service.entitiy.entity.relation.TbEntityRelationService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import java.util.List;
@ -54,7 +55,7 @@ import static org.thingsboard.server.controller.ControllerConstants.RELATION_TYP
@RequiredArgsConstructor
public class EntityRelationController extends BaseController {
private final TbEntityRelationService tbEntityRelationService;
private final TbEntityRelationService tbEntityRelationService;
public static final String TO_TYPE = "toType";
public static final String FROM_ID = "fromId";
@ -80,13 +81,13 @@ public class EntityRelationController extends BaseController {
public void saveRelation(@ApiParam(value = "A JSON value representing the relation.", required = true)
@RequestBody EntityRelation relation) throws ThingsboardException {
checkNotNull(relation);
checkEntityId(relation.getFrom(), Operation.WRITE);
checkEntityId(relation.getTo(), Operation.WRITE);
checkCanCreateRelation(relation.getFrom());
checkCanCreateRelation(relation.getTo());
if (relation.getTypeGroup() == null) {
relation.setTypeGroup(RelationTypeGroup.COMMON);
}
tbEntityRelationService.save(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
tbEntityRelationService.save(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
}
@ApiOperation(value = "Delete Relation (deleteRelation)",
@ -107,11 +108,11 @@ public class EntityRelationController extends BaseController {
checkParameter(TO_TYPE, strToType);
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(fromId, Operation.WRITE);
checkEntityId(toId, Operation.WRITE);
checkCanCreateRelation(fromId);
checkCanCreateRelation(toId);
RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
EntityRelation relation = new EntityRelation(fromId, toId, strRelationType, relationTypeGroup);
tbEntityRelationService.delete(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
}
@ -127,7 +128,7 @@ public class EntityRelationController extends BaseController {
checkParameter("entityType", strType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId);
checkEntityId(entityId, Operation.WRITE);
tbEntityRelationService.deleteRelations (getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser());
tbEntityRelationService.deleteRelations(getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser());
}
@ApiOperation(value = "Get Relation (getRelation)",
@ -341,6 +342,14 @@ public class EntityRelationController extends BaseController {
}
}
private void checkCanCreateRelation(EntityId entityId) throws ThingsboardException {
SecurityUser currentUser = getCurrentUser();
var isTenantAdminAndRelateToSelf = currentUser.isTenantAdmin() && currentUser.getTenantId().equals(entityId);
if (!isTenantAdminAndRelateToSelf) {
checkEntityId(entityId, Operation.WRITE);
}
}
private <T extends EntityRelation> List<T> filterRelationsByReadPermission(List<T> relationsByQuery) {
return relationsByQuery.stream().filter(relationByQuery -> {
try {

14
application/src/main/java/org/thingsboard/server/controller/EntityViewController.java

@ -48,7 +48,7 @@ import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.entityView.TbEntityViewService;
import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -132,14 +132,16 @@ public class EntityViewController extends BaseController {
}
@ApiOperation(value = "Save or update entity view (saveEntityView)",
notes = ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION,
notes = ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Entity View entity." +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView", method = RequestMethod.POST)
@ResponseBody
public EntityView saveEntityView(
@ApiParam(value = "A JSON object representing the entity view.")
@RequestBody EntityView entityView) throws ThingsboardException {
@RequestBody EntityView entityView) throws Exception {
entityView.setTenantId(getCurrentUser().getTenantId());
EntityView existingEntityView = null;
if (entityView.getId() == null) {
@ -452,7 +454,8 @@ public class EntityViewController extends BaseController {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
checkEntityViewId(entityViewId, Operation.READ);
return tbEntityViewService.assignEntityViewToEdge(getTenantId(), getCurrentUser().getCustomerId(), entityViewId, edge, getCurrentUser());
return tbEntityViewService.assignEntityViewToEdge(getTenantId(), getCurrentUser().getCustomerId(),
entityViewId, edge, getCurrentUser());
}
@ApiOperation(value = "Unassign entity view from edge (unassignEntityViewFromEdge)",
@ -476,7 +479,8 @@ public class EntityViewController extends BaseController {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
EntityView entityView = checkEntityViewId(entityViewId, Operation.READ);
return tbEntityViewService.unassignEntityViewFromEdge(getTenantId(), entityView.getCustomerId(), entityView, edge, getCurrentUser());
return tbEntityViewService.unassignEntityViewFromEdge(getTenantId(), entityView.getCustomerId(), entityView,
edge, getCurrentUser());
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")

21
application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java

@ -43,10 +43,12 @@ import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.otaPackageController.TbOtaPackageService;
import org.thingsboard.server.service.entitiy.ota.TbOtaPackageService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.io.IOException;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
@ -158,8 +160,6 @@ public class OtaPackageController extends BaseController {
checkEntity(otaPackageInfo.getId(), otaPackageInfo, Resource.OTA_PACKAGE);
return tbOtaPackageService.save(otaPackageInfo, getCurrentUser());
}
@ApiOperation(value = "Save OTA Package data (saveOtaPackageData)",
@ -176,19 +176,15 @@ public class OtaPackageController extends BaseController {
@ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES)
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@ApiParam(value = "OTA Package data.")
@RequestPart MultipartFile file) throws ThingsboardException {
@RequestPart MultipartFile file) throws ThingsboardException, IOException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo otaPackageInfo = checkOtaPackageInfoId(otaPackageId, Operation.READ);
try {
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase());
byte[] data = file.getBytes();
return tbOtaPackageService.saveOtaPackageData(otaPackageInfo, checksum, checksumAlgorithm,
data, file.getOriginalFilename(), file.getContentType(), getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase());
byte[] data = file.getBytes();
return tbOtaPackageService.saveOtaPackageData(otaPackageInfo, checksum, checksumAlgorithm,
data, file.getOriginalFilename(), file.getContentType(), getCurrentUser());
}
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
@ -260,7 +256,6 @@ public class OtaPackageController extends BaseController {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo otaPackageInfo = checkOtaPackageInfoId(otaPackageId, Operation.DELETE);
tbOtaPackageService.delete(otaPackageInfo, getCurrentUser());
}

126
application/src/main/java/org/thingsboard/server/controller/QueueController.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@ -37,6 +39,22 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.util.UUID;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_NAME_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@RestController
@TbCoreComponent
@RequestMapping("/api")
@ -45,82 +63,100 @@ public class QueueController extends BaseController {
private final TbQueueService tbQueueService;
@ApiOperation(value = "Get Queues (getTenantQueuesByServiceType)",
notes = "Returns a page of queues registered in the platform. " +
PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Queue> getTenantQueuesByServiceType(@RequestParam String serviceType,
public PageData<Queue> getTenantQueuesByServiceType(@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES, required = true)
@RequestParam String serviceType,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("serviceType", serviceType);
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
ServiceType type = ServiceType.valueOf(serviceType);
switch (type) {
case TB_RULE_ENGINE:
return queueService.findQueuesByTenantId(getTenantId(), pageLink);
default:
return new PageData<>();
}
} catch (Exception e) {
throw handleException(e);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
ServiceType type = ServiceType.valueOf(serviceType);
switch (type) {
case TB_RULE_ENGINE:
return queueService.findQueuesByTenantId(getTenantId(), pageLink);
default:
return new PageData<>();
}
}
@ApiOperation(value = "Get Queue (getQueueById)",
notes = "Fetch the Queue object based on the provided Queue Id. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.GET)
@ResponseBody
public Queue getQueueById(@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
public Queue getQueueById(@ApiParam(value = QUEUE_ID_PARAM_DESCRIPTION)
@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
checkParameter("queueId", queueIdStr);
try {
QueueId queueId = new QueueId(UUID.fromString(queueIdStr));
checkQueueId(queueId, Operation.READ);
return checkNotNull(queueService.findQueueById(getTenantId(), queueId));
} catch (
Exception e) {
throw handleException(e);
}
QueueId queueId = new QueueId(UUID.fromString(queueIdStr));
checkQueueId(queueId, Operation.READ);
return checkNotNull(queueService.findQueueById(getTenantId(), queueId));
}
@ApiOperation(value = "Get Queue (getQueueByName)",
notes = "Fetch the Queue object based on the provided Queue name. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/name/{queueName}", method = RequestMethod.GET)
@ResponseBody
public Queue getQueueByName(@ApiParam(value = QUEUE_NAME_PARAM_DESCRIPTION)
@PathVariable("queueName") String queueName) throws ThingsboardException {
checkParameter("queueName", queueName);
return checkNotNull(queueService.findQueueByTenantIdAndName(getTenantId(), queueName));
}
@ApiOperation(value = "Create Or Update Queue (saveQueue)",
notes = "Create or update the Queue. When creating queue, platform generates Queue Id as " + UUID_WIKI_LINK +
"Specify existing Queue id to update the queue. " +
"Referencing non-existing Queue Id will cause 'Not Found' error." +
"\n\nQueue name is unique in the scope of sysadmin. " +
"Remove 'id', 'tenantId' from the request body example (below) to create new Queue entity. " +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST)
@ResponseBody
public Queue saveQueue(@RequestBody Queue queue,
public Queue saveQueue(@ApiParam(value = "A JSON value representing the queue.")
@RequestBody Queue queue,
@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES, required = true)
@RequestParam String serviceType) throws ThingsboardException {
checkParameter("serviceType", serviceType);
try {
queue.setTenantId(getCurrentUser().getTenantId());
queue.setTenantId(getCurrentUser().getTenantId());
checkEntity(queue.getId(), queue, Resource.QUEUE);
checkEntity(queue.getId(), queue, Resource.QUEUE);
ServiceType type = ServiceType.valueOf(serviceType);
switch (type) {
case TB_RULE_ENGINE:
queue.setTenantId(getTenantId());
Queue savedQueue = tbQueueService.saveQueue(queue);
checkNotNull(savedQueue);
return savedQueue;
default:
return null;
}
} catch (Exception e) {
throw handleException(e);
ServiceType type = ServiceType.valueOf(serviceType);
switch (type) {
case TB_RULE_ENGINE:
queue.setTenantId(getTenantId());
Queue savedQueue = tbQueueService.saveQueue(queue);
checkNotNull(savedQueue);
return savedQueue;
default:
return null;
}
}
@ApiOperation(value = "Delete Queue (deleteQueue)", notes = "Deletes the Queue. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteQueue(@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
public void deleteQueue(@ApiParam(value = QUEUE_ID_PARAM_DESCRIPTION)
@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
checkParameter("queueId", queueIdStr);
try {
QueueId queueId = new QueueId(toUUID(queueIdStr));
checkQueueId(queueId, Operation.DELETE);
tbQueueService.deleteQueue(getTenantId(), queueId);
} catch (Exception e) {
throw handleException(e);
}
QueueId queueId = new QueueId(toUUID(queueIdStr));
checkQueueId(queueId, Operation.DELETE);
tbQueueService.deleteQueue(getTenantId(), queueId);
}
}

37
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -70,6 +70,7 @@ import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -226,18 +227,19 @@ public class RuleChainController extends BaseController {
"The newly created Rule Chain Id will be present in the response. " +
"Specify existing Rule Chain id to update the rule chain. " +
"Referencing non-existing rule chain Id will cause 'Not Found' error." +
"\n\n" + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
"\n\n" + RULE_CHAIN_DESCRIPTION +
"Remove 'id', 'tenantId' from the request body example (below) to create new Rule Chain entity." +
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody
public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the rule chain.")
@RequestBody RuleChain ruleChain) throws ThingsboardException {
@RequestBody RuleChain ruleChain) throws Exception {
ruleChain.setTenantId(getCurrentUser().getTenantId());
checkEntity(ruleChain.getId(), ruleChain, Resource.RULE_CHAIN);
return tbRuleChainService.save(ruleChain, getCurrentUser());
}
}
@ApiOperation(value = "Create Default Rule Chain",
notes = "Create rule chain from template, based on the specified name in the request. " +
@ -247,12 +249,11 @@ public class RuleChainController extends BaseController {
@ResponseBody
public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the request.")
@RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException {
@RequestBody DefaultRuleChainCreateRequest request) throws Exception {
checkNotNull(request);
checkParameter(request.getName(), "name");
return tbRuleChainService.saveDefaultByName(getTenantId(), request, getCurrentUser());
}
}
@ApiOperation(value = "Set Root Rule Chain (setRootRuleChain)",
notes = "Makes the rule chain to be root rule chain. Updates previous root rule chain as well. " + TENANT_AUTHORITY_PARAGRAPH)
@ -265,8 +266,7 @@ public class RuleChainController extends BaseController {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
return tbRuleChainService.setRootRuleChain(getTenantId(),ruleChain, getCurrentUser());
return tbRuleChainService.setRootRuleChain(getTenantId(), ruleChain, getCurrentUser());
}
@ApiOperation(value = "Update Rule Chain Metadata",
@ -279,7 +279,7 @@ public class RuleChainController extends BaseController {
@RequestBody RuleChainMetaData ruleChainMetaData,
@ApiParam(value = "Update related rule nodes.")
@RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated
) throws ThingsboardException {
) throws Exception {
TenantId tenantId = getTenantId();
if (debugPerTenantEnabled) {
ConcurrentMap<TenantId, DebugTbRateLimits> debugPerTenantLimits = actorContext.getDebugPerTenantLimits();
@ -290,9 +290,8 @@ public class RuleChainController extends BaseController {
}
RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
return tbRuleChainService.saveRuleChainMetaData(tenantId, ruleChain, ruleChainMetaData, updateRelated,
getCurrentUser());
}
return tbRuleChainService.saveRuleChainMetaData(tenantId, ruleChain, ruleChainMetaData, updateRelated, getCurrentUser());
}
@ApiOperation(value = "Get Rule Chains (getRuleChains)",
notes = "Returns a page of Rule Chains owned by tenant. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@ -335,11 +334,10 @@ public class RuleChainController extends BaseController {
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.DELETE);
tbRuleChainService.delete(ruleChain, getCurrentUser());
}
}
@ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)",
notes = "Gets the input message from the debug events for specified Rule Chain Id. " +
@ -532,7 +530,7 @@ public class RuleChainController extends BaseController {
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.assignRuleChainToEdge(getTenantId(), ruleChain, edge, getCurrentUser());
}
}
@ApiOperation(value = "Unassign rule chain from edge (unassignRuleChainFromEdge)",
notes = "Clears assignment of the rule chain to the edge. " +
@ -554,7 +552,7 @@ public class RuleChainController extends BaseController {
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.unassignRuleChainFromEdge(getTenantId(), ruleChain, edge, getCurrentUser());
}
}
@ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)",
notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@ -612,7 +610,7 @@ public class RuleChainController extends BaseController {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
return tbRuleChainService.setAutoAssignToEdgeRuleChain(getTenantId(), ruleChain, getCurrentUser());
}
}
@ApiOperation(value = "Unset Auto Assign To Edge Rule Chain (unsetAutoAssignToEdgeRuleChain)",
notes = "Removes the rule chain from the list of rule chains that are going to be automatically assigned for any new edge that will be created. " +
@ -625,9 +623,8 @@ public class RuleChainController extends BaseController {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
return tbRuleChainService.unsetAutoAssignToEdgeRuleChain(getTenantId(), ruleChain, getCurrentUser());
}
}
// TODO: @voba refactor this - add new config to edge rule chain to set it as auto-assign
@ApiOperation(value = "Get Auto Assign To Edge Rule Chains (getAutoAssignToEdgeRuleChains)",

8
application/src/main/java/org/thingsboard/server/controller/TbResourceController.java

@ -71,7 +71,7 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@RequiredArgsConstructor
public class TbResourceController extends BaseController {
private final TbResourceService tbResourceService;
private final TbResourceService tbResourceService;
public static final String RESOURCE_ID = "resourceId";
@ -139,14 +139,16 @@ public class TbResourceController extends BaseController {
"The newly created Resource id will be present in the response. " +
"Specify existing Resource id to update the Resource. " +
"Referencing non-existing Resource Id will cause 'Not Found' error. " +
"\n\nResource combination of the title with the key is unique in the scope of tenant. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
"\n\nResource combination of the title with the key is unique in the scope of tenant. " +
"Remove 'id', 'tenantId' from the request body example (below) to create new Resource entity." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json",
consumes = "application/json")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource", method = RequestMethod.POST)
@ResponseBody
public TbResource saveResource(@ApiParam(value = "A JSON value representing the Resource.")
@RequestBody TbResource resource) throws ThingsboardException {
@RequestBody TbResource resource) throws Exception {
resource.setTenantId(getTenantId());
checkEntity(resource.getId(), resource, Resource.TB_RESOURCE);
return tbResourceService.save(resource, getCurrentUser());

39
application/src/main/java/org/thingsboard/server/controller/TelemetryController.java

@ -888,48 +888,29 @@ public class TelemetryController extends BaseController {
}
private void logTimeseriesDeleted(SecurityUser user, EntityId entityId, List<String> keys, long startTs, long endTs, Throwable e) {
try {
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_DELETED, toException(e),
keys, startTs, endTs);
} catch (ThingsboardException te) {
log.warn("Failed to log timeseries delete", te);
}
notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.TIMESERIES_DELETED, user,
toException(e), keys, startTs, endTs);
}
private void logTelemetryUpdated(SecurityUser user, EntityId entityId, List<TsKvEntry> telemetry, Throwable e) {
try {
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_UPDATED, toException(e), telemetry);
} catch (ThingsboardException te) {
log.warn("Failed to log telemetry update");
}
notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.TIMESERIES_UPDATED, user,
toException(e), telemetry);
}
private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
try {
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_DELETED, toException(e),
scope, keys);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes delete", te);
}
notificationEntityService.logEntityAction(user.getTenantId(), (UUIDBased & EntityId) entityId,
ActionType.ATTRIBUTES_DELETED, user, toException(e), scope, keys);
}
private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) {
try {
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e),
scope, attributes);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes update", te);
}
notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.ATTRIBUTES_UPDATED, user,
toException(e), scope, attributes);
}
private void logAttributesRead(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
try {
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_READ, toException(e),
scope, keys);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes read", te);
}
notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.ATTRIBUTES_READ, user,
toException(e), scope, keys);
}
private ListenableFuture<List<AttributeKvEntry>> mergeAllAttributesFutures(List<ListenableFuture<List<AttributeKvEntry>>> futures) {

5
application/src/main/java/org/thingsboard/server/controller/TenantController.java

@ -115,12 +115,13 @@ public class TenantController extends BaseController {
"The newly created Tenant Id will be present in the response. " +
"Specify existing Tenant Id id to update the Tenant. " +
"Referencing non-existing Tenant Id will cause 'Not Found' error." +
"Remove 'id', 'tenantId' from the request body example (below) to create new Tenant entity." +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant", method = RequestMethod.POST)
@ResponseBody
public Tenant saveTenant(@ApiParam(value = "A JSON value representing the tenant.")
@RequestBody Tenant tenant) throws ThingsboardException {
@RequestBody Tenant tenant) throws Exception {
checkEntity(tenant.getId(), tenant, Resource.TENANT);
return tbTenantService.save(tenant);
}
@ -131,7 +132,7 @@ public class TenantController extends BaseController {
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteTenant(@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
@PathVariable(TENANT_ID) String strTenantId) throws Exception {
checkParameter(TENANT_ID, strTenantId);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
Tenant tenant = checkTenantId(tenantId, Operation.DELETE);

34
application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java

@ -32,13 +32,11 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.tenant_profile.TbTenantProfileService;
import org.thingsboard.server.service.entitiy.tenant.profile.TbTenantProfileService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -130,7 +128,6 @@ public class TenantProfileController extends BaseController {
"{\n" +
" \"name\": \"Default\",\n" +
" \"description\": \"Default tenant profile\",\n" +
" \"isolatedTbCore\": false,\n" +
" \"isolatedTbRuleEngine\": false,\n" +
" \"profileData\": {\n" +
" \"configuration\": {\n" +
@ -167,30 +164,23 @@ public class TenantProfileController extends BaseController {
" \"default\": true\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
"Remove 'id', from the request body example (below) to create new Tenant Profile entity." +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile", method = RequestMethod.POST)
@ResponseBody
public TenantProfile saveTenantProfile(
@ApiParam(value = "A JSON value representing the tenant profile.")
@RequestBody TenantProfile tenantProfile) throws ThingsboardException {
public TenantProfile saveTenantProfile(@ApiParam(value = "A JSON value representing the tenant profile.")
@RequestBody TenantProfile tenantProfile) throws ThingsboardException {
try {
boolean newTenantProfile = tenantProfile.getId() == null;
TenantProfile oldProfile;
if (newTenantProfile) {
accessControlService
.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
if (tenantProfile.getId() == null) {
accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
oldProfile = null;
} else {
oldProfile = checkTenantProfileId(tenantProfile.getId(), Operation.WRITE);
}
tenantProfile = checkNotNull(tbTenantProfileService.saveTenantProfile(getTenantId(), tenantProfile, oldProfile));
tenantProfileCache.put(tenantProfile);
tbClusterService.onTenantProfileChange(tenantProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(TenantId.SYS_TENANT_ID, tenantProfile.getId(),
newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
return tenantProfile;
return tbTenantProfileService.save(getTenantId(), tenantProfile, oldProfile);
} catch (Exception e) {
throw handleException(e);
}
@ -201,15 +191,13 @@ public class TenantProfileController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteTenantProfile(
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
public void deleteTenantProfile(@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
try {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE);
tenantProfileService.deleteTenantProfile(getTenantId(), tenantProfileId);
tbClusterService.onTenantProfileDelete(profile, null);
tbTenantProfileService.delete(getTenantId(), profile);
} catch (Exception e) {
throw handleException(e);
}

2
application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java → application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java

@ -50,7 +50,7 @@ import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
@RequestMapping("/api/2fa")
@TbCoreComponent
@RequiredArgsConstructor
public class TwoFaConfigController extends BaseController {
public class TwoFactorAuthConfigController extends BaseController {
private final TwoFaConfigManager twoFaConfigManager;
private final TwoFactorAuthService twoFactorAuthService;

12
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -102,9 +102,9 @@ public class UserController extends BaseController {
@ApiOperation(value = "Get User (getUserById)",
notes = "Fetch the User object based on the provided User Id. " +
"If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " +
"If the user has the authority of 'TENANT_ADMIN', the server checks that the requested user is owned by the same tenant. " +
"If the user has the authority of 'CUSTOMER_USER', the server checks that the requested user is owned by the same customer.")
"If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " +
"If the user has the authority of 'TENANT_ADMIN', the server checks that the requested user is owned by the same tenant. " +
"If the user has the authority of 'CUSTOMER_USER', the server checks that the requested user is owned by the same customer.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
@ResponseBody
@ -176,7 +176,9 @@ public class UserController extends BaseController {
"The newly created User Id will be present in the response. " +
"Specify existing User Id to update the device. " +
"Referencing non-existing User Id will cause 'Not Found' error." +
"\n\nDevice email is unique for entire platform setup.")
"\n\nDevice email is unique for entire platform setup." +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new User entity." +
"\n\nAvailable for users with 'SYS_ADMIN', 'TENANT_ADMIN' or 'CUSTOMER_USER' authority.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
@ -190,7 +192,7 @@ public class UserController extends BaseController {
}
checkEntity(user.getId(), user, Resource.USER);
return tbUserService.save(getTenantId(), getCurrentUser().getCustomerId(), user, sendActivationMail, request, getCurrentUser());
}
}
@ApiOperation(value = "Send or re-send the activation email",
notes = "Force send the activation email to the user. Useful to resend the email if user has accidentally deleted it. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)

32
application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java

@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetType;
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.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
@ -52,7 +53,7 @@ import static org.thingsboard.server.controller.ControllerConstants.WIDGET_TYPE_
@RestController
@TbCoreComponent
@RequestMapping("/api")
public class WidgetTypeController extends BaseController {
public class WidgetTypeController extends AutoCommitController {
private static final String WIDGET_TYPE_DESCRIPTION = "Widget Type represents the template for widget creation. Widget Type and Widget are similar to class and object in OOP theory.";
private static final String WIDGET_TYPE_DETAILS_DESCRIPTION = "Widget Type Details extend Widget Type and add image and description properties. " +
@ -84,8 +85,9 @@ public class WidgetTypeController extends BaseController {
"Specify existing Widget Type id to update the Widget Type. " +
"Referencing non-existing Widget Type Id will cause 'Not Found' error." +
"\n\nWidget Type alias is unique in the scope of Widget Bundle. " +
"Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create request is sent by user with 'SYS_ADMIN' authority."
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
"Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create request is sent by user with 'SYS_ADMIN' authority." +
"Remove 'id', 'tenantId' rom the request body example (below) to create new Widget Type entity." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/widgetType", method = RequestMethod.POST)
@ResponseBody
@ -93,15 +95,23 @@ public class WidgetTypeController extends BaseController {
@ApiParam(value = "A JSON value representing the Widget Type Details.", required = true)
@RequestBody WidgetTypeDetails widgetTypeDetails) throws ThingsboardException {
try {
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
widgetTypeDetails.setTenantId(TenantId.SYS_TENANT_ID);
} else {
widgetTypeDetails.setTenantId(getCurrentUser().getTenantId());
widgetTypeDetails.setTenantId(currentUser.getTenantId());
}
checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE);
WidgetTypeDetails savedWidgetTypeDetails = widgetTypeService.saveWidgetType(widgetTypeDetails);
if (!Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(widgetTypeDetails.getTenantId(), widgetTypeDetails.getBundleAlias());
if (widgetsBundle != null) {
autoCommit(currentUser, widgetsBundle.getId());
}
}
sendEntityNotificationMsg(getTenantId(), savedWidgetTypeDetails.getId(),
widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
@ -121,9 +131,17 @@ public class WidgetTypeController extends BaseController {
@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException {
checkParameter("widgetTypeId", strWidgetTypeId);
try {
var currentUser = getCurrentUser();
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
checkWidgetTypeId(widgetTypeId, Operation.DELETE);
widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId);
WidgetTypeDetails wtd = checkWidgetTypeId(widgetTypeId, Operation.DELETE);
widgetTypeService.deleteWidgetType(currentUser.getTenantId(), widgetTypeId);
if (wtd != null && !Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(wtd.getTenantId(), wtd.getBundleAlias());
if (widgetsBundle != null) {
autoCommit(currentUser, widgetsBundle.getId());
}
}
sendEntityNotificationMsg(getTenantId(), widgetTypeId, EdgeEventActionType.DELETED);

27
application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java

@ -36,7 +36,7 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.widgetsBundle.TbWidgetsBundleService;
import org.thingsboard.server.service.entitiy.widgets.bundle.TbWidgetsBundleService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -89,24 +89,25 @@ public class WidgetsBundleController extends BaseController {
"Specify existing Widget Bundle id to update the Widget Bundle. " +
"Referencing non-existing Widget Bundle Id will cause 'Not Found' error." +
"\n\nWidget Bundle alias is unique in the scope of tenant. " +
"Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create bundle request is sent by user with 'SYS_ADMIN' authority."
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
"Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create bundle request is sent by user with 'SYS_ADMIN' authority." +
"Remove 'id', 'tenantId' from the request body example (below) to create new Widgets Bundle entity." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST)
@ResponseBody
public WidgetsBundle saveWidgetsBundle(
@ApiParam(value = "A JSON value representing the Widget Bundle.", required = true)
@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException {
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID);
} else {
widgetsBundle.setTenantId(getCurrentUser().getTenantId());
}
@RequestBody WidgetsBundle widgetsBundle) throws Exception {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID);
} else {
widgetsBundle.setTenantId(currentUser.getTenantId());
}
checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE);
checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE);
return tbWidgetsBundleService.save(widgetsBundle, getCurrentUser());
return tbWidgetsBundleService.save(widgetsBundle, currentUser);
}
@ApiOperation(value = "Delete widgets bundle (deleteWidgetsBundle)",
@ -120,7 +121,7 @@ public class WidgetsBundleController extends BaseController {
checkParameter("widgetsBundleId", strWidgetsBundleId);
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
WidgetsBundle widgetsBundle = checkWidgetsBundleId(widgetsBundleId, Operation.DELETE);
tbWidgetsBundleService.delete(widgetsBundle, getCurrentUser());
tbWidgetsBundleService.delete(widgetsBundle);
}
@ApiOperation(value = "Get Widget Bundles (getWidgetsBundles)",

67
application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java

@ -16,12 +16,12 @@
package org.thingsboard.server.controller.plugin;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.BeanCreationNotAllowedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
@ -34,10 +34,10 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.config.WebSocketConfiguration;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.telemetry.DefaultTelemetryWebSocketService;
import org.thingsboard.server.service.telemetry.SessionEvent;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketMsgEndpoint;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketService;
@ -72,22 +72,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
@Autowired
private TelemetryWebSocketService webSocketService;
@Autowired
private TbTenantProfileCache tenantProfileCache;
@Value("${server.ws.send_timeout:5000}")
private long sendTimeout;
@Value("${server.ws.limits.max_sessions_per_tenant:0}")
private int maxSessionsPerTenant;
@Value("${server.ws.limits.max_sessions_per_customer:0}")
private int maxSessionsPerCustomer;
@Value("${server.ws.limits.max_sessions_per_regular_user:0}")
private int maxSessionsPerRegularUser;
@Value("${server.ws.limits.max_sessions_per_public_user:0}")
private int maxSessionsPerPublicUser;
@Value("${server.ws.limits.max_queue_per_ws_session:1000}")
private int maxMsgQueuePerSession;
@Value("${server.ws.limits.max_updates_per_session:}")
private String perSessionUpdatesConfiguration;
@Value("${server.ws.ping_timeout:30000}")
private long pingTimeout;
@ -144,10 +133,13 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
String internalSessionId = session.getId();
TelemetryWebSocketSessionRef sessionRef = toRef(session);
String externalSessionId = sessionRef.getSessionId();
if (!checkLimits(session, sessionRef)) {
return;
}
internalSessionMap.put(internalSessionId, new SessionMetaData(session, sessionRef, maxMsgQueuePerSession));
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
internalSessionMap.put(internalSessionId, new SessionMetaData(session, sessionRef, tenantProfileConfiguration.getWsMsgQueueLimitPerSession() > 0 ?
tenantProfileConfiguration.getWsMsgQueueLimitPerSession() : 500));
externalSessionMap.put(externalSessionId, internalSessionId);
processInWebSocketService(sessionRef, SessionEvent.onEstablished());
@ -323,8 +315,9 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
if (internalId != null) {
SessionMetaData sessionMd = internalSessionMap.get(internalId);
if (sessionMd != null) {
if (!StringUtils.isEmpty(perSessionUpdatesConfiguration)) {
TbRateLimits rateLimits = perSessionUpdateLimits.computeIfAbsent(sessionRef.getSessionId(), sid -> new TbRateLimits(perSessionUpdatesConfiguration));
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
if (StringUtils.isNotEmpty(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit())) {
TbRateLimits rateLimits = perSessionUpdateLimits.computeIfAbsent(sessionRef.getSessionId(), sid -> new TbRateLimits(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit()));
if (!rateLimits.tryConsume()) {
if (blacklistedSessions.putIfAbsent(externalId, sessionRef) == null) {
log.info("[{}][{}][{}] Failed to process session update. Max session updates limit reached"
@ -336,6 +329,8 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
log.debug("[{}][{}][{}] Session is no longer blacklisted.", sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), externalId);
blacklistedSessions.remove(externalId);
}
} else {
perSessionUpdateLimits.remove(sessionRef.getSessionId());
}
sessionMd.sendMsg(msg);
} else {
@ -380,11 +375,17 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
private boolean checkLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) throws Exception {
var tenantProfileConfiguration =
tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
if (tenantProfileConfiguration == null) {
return true;
}
String sessionId = session.getId();
if (maxSessionsPerTenant > 0) {
if (tenantProfileConfiguration.getMaxWsSessionsPerTenant() > 0) {
Set<String> tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet());
synchronized (tenantSessions) {
if (tenantSessions.size() < maxSessionsPerTenant) {
if (tenantSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerTenant()) {
tenantSessions.add(sessionId);
} else {
log.info("[{}][{}][{}] Failed to start session. Max tenant sessions limit reached"
@ -396,10 +397,10 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
if (sessionRef.getSecurityCtx().isCustomerUser()) {
if (maxSessionsPerCustomer > 0) {
if (tenantProfileConfiguration.getMaxWsSessionsPerCustomer() > 0) {
Set<String> customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet());
synchronized (customerSessions) {
if (customerSessions.size() < maxSessionsPerCustomer) {
if (customerSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerCustomer()) {
customerSessions.add(sessionId);
} else {
log.info("[{}][{}][{}] Failed to start session. Max customer sessions limit reached"
@ -409,10 +410,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
}
}
if (maxSessionsPerRegularUser > 0 && UserPrincipal.Type.USER_NAME.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
if (tenantProfileConfiguration.getMaxWsSessionsPerRegularUser() > 0
&& UserPrincipal.Type.USER_NAME.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
Set<String> regularUserSessions = regularUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (regularUserSessions) {
if (regularUserSessions.size() < maxSessionsPerRegularUser) {
if (regularUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerRegularUser()) {
regularUserSessions.add(sessionId);
} else {
log.info("[{}][{}][{}] Failed to start session. Max regular user sessions limit reached"
@ -422,10 +424,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
}
}
if (maxSessionsPerPublicUser > 0 && UserPrincipal.Type.PUBLIC_ID.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
if (tenantProfileConfiguration.getMaxWsSessionsPerPublicUser() > 0
&& UserPrincipal.Type.PUBLIC_ID.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
Set<String> publicUserSessions = publicUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (publicUserSessions) {
if (publicUserSessions.size() < maxSessionsPerPublicUser) {
if (publicUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerPublicUser()) {
publicUserSessions.add(sessionId);
} else {
log.info("[{}][{}][{}] Failed to start session. Max public user sessions limit reached"
@ -440,29 +443,31 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
private void cleanupLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) {
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
String sessionId = session.getId();
perSessionUpdateLimits.remove(sessionRef.getSessionId());
blacklistedSessions.remove(sessionRef.getSessionId());
if (maxSessionsPerTenant > 0) {
if (tenantProfileConfiguration.getMaxWsSessionsPerTenant() > 0) {
Set<String> tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet());
synchronized (tenantSessions) {
tenantSessions.remove(sessionId);
}
}
if (sessionRef.getSecurityCtx().isCustomerUser()) {
if (maxSessionsPerCustomer > 0) {
if (tenantProfileConfiguration.getMaxWsSessionsPerCustomer() > 0) {
Set<String> customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet());
synchronized (customerSessions) {
customerSessions.remove(sessionId);
}
}
if (maxSessionsPerRegularUser > 0 && UserPrincipal.Type.USER_NAME.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
if (tenantProfileConfiguration.getMaxWsSessionsPerRegularUser() > 0 && UserPrincipal.Type.USER_NAME.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
Set<String> regularUserSessions = regularUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (regularUserSessions) {
regularUserSessions.remove(sessionId);
}
}
if (maxSessionsPerPublicUser > 0 && UserPrincipal.Type.PUBLIC_ID.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
if (tenantProfileConfiguration.getMaxWsSessionsPerPublicUser() > 0 && UserPrincipal.Type.PUBLIC_ID.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) {
Set<String> publicUserSessions = publicUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (publicUserSessions) {
publicUserSessions.remove(sessionId);

2
application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java

@ -34,7 +34,7 @@ public class ThingsboardCredentialsExpiredResponse extends ThingsboardErrorRespo
return new ThingsboardCredentialsExpiredResponse(message, resetToken);
}
@ApiModelProperty(position = 5, value = "Password reset token", readOnly = true)
@ApiModelProperty(position = 5, value = "Password reset token", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public String getResetToken() {
return resetToken;
}

8
application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java

@ -46,12 +46,12 @@ public class ThingsboardErrorResponse {
return new ThingsboardErrorResponse(message, errorCode, status);
}
@ApiModelProperty(position = 1, value = "HTTP Response Status Code", example = "401", readOnly = true)
@ApiModelProperty(position = 1, value = "HTTP Response Status Code", example = "401", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Integer getStatus() {
return status.value();
}
@ApiModelProperty(position = 2, value = "Error message", example = "Authentication failed", readOnly = true)
@ApiModelProperty(position = 2, value = "Error message", example = "Authentication failed", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public String getMessage() {
return message;
}
@ -69,12 +69,12 @@ public class ThingsboardErrorResponse {
"\n\n* `34` - Too many updates (Too many updates over Websocket session)" +
"\n\n* `40` - Subscription violation (HTTP: 403 - Forbidden)",
example = "10", dataType = "integer",
readOnly = true)
accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public ThingsboardErrorCode getErrorCode() {
return errorCode;
}
@ApiModelProperty(position = 4, value = "Timestamp", readOnly = true)
@ApiModelProperty(position = 4, value = "Timestamp", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Date getTimestamp() {
return timestamp;
}

11
application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java

@ -22,13 +22,14 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@ -41,13 +42,11 @@ import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.cluster.TbClusterService;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@TbCoreComponent
@Service
@RequiredArgsConstructor
@Slf4j
@ -212,7 +211,7 @@ public class EntityActionService {
}
}
public <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId,
public <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) {
if (customerId == null || customerId.isNullUid()) {
customerId = user.getCustomerId();
@ -223,6 +222,9 @@ public class EntityActionService {
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo);
}
public void sendEntityNotificationMsgToEdge(TenantId tenantId, EntityId entityId, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdge(tenantId, null, entityId, null, null, action);
}
private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) {
T result = null;
@ -267,4 +269,5 @@ public class EntityActionService {
entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString());
}
}
}

76
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultRateLimitService.java

@ -0,0 +1,76 @@
/**
* Copyright © 2016-2022 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.apiusage;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
@Service
@RequiredArgsConstructor
public class DefaultRateLimitService implements RateLimitService {
private final TbTenantProfileCache tenantProfileCache;
private final Map<String, Map<TenantId, TbRateLimits>> rateLimits = new ConcurrentHashMap<>();
@Override
public boolean checkEntityExportLimit(TenantId tenantId) {
return checkLimit(tenantId, "entityExport", DefaultTenantProfileConfiguration::getTenantEntityExportRateLimit);
}
@Override
public boolean checkEntityImportLimit(TenantId tenantId) {
return checkLimit(tenantId, "entityImport", DefaultTenantProfileConfiguration::getTenantEntityImportRateLimit);
}
private boolean checkLimit(TenantId tenantId, String rateLimitsKey, Function<DefaultTenantProfileConfiguration, String> rateLimitConfigExtractor) {
String rateLimitConfig = tenantProfileCache.get(tenantId).getProfileConfiguration()
.map(rateLimitConfigExtractor).orElse(null);
Map<TenantId, TbRateLimits> rateLimits = this.rateLimits.get(rateLimitsKey);
if (StringUtils.isEmpty(rateLimitConfig)) {
if (rateLimits != null) {
rateLimits.remove(tenantId);
if (rateLimits.isEmpty()) {
this.rateLimits.remove(rateLimitsKey);
}
}
return true;
}
if (rateLimits == null) {
rateLimits = new ConcurrentHashMap<>();
this.rateLimits.put(rateLimitsKey, rateLimits);
}
TbRateLimits rateLimit = rateLimits.get(tenantId);
if (rateLimit == null || !rateLimit.getConfiguration().equals(rateLimitConfig)) {
rateLimit = new TbRateLimits(rateLimitConfig);
rateLimits.put(tenantId, rateLimit);
}
return rateLimit.tryConsume();
}
}

11
application/src/main/java/org/thingsboard/server/service/entitiy/tenant_profile/TbTenantProfileService.java → application/src/main/java/org/thingsboard/server/service/apiusage/RateLimitService.java

@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.tenant_profile;
package org.thingsboard.server.service.apiusage;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.TenantId;
public interface TbTenantProfileService {
TenantProfile saveTenantProfile(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile);
public interface RateLimitService {
boolean checkEntityExportLimit(TenantId tenantId);
boolean checkEntityImportLimit(TenantId tenantId);
}

4
application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java

@ -26,9 +26,9 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.importing.AbstractBulkImportService;
import org.thingsboard.server.service.importing.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Map;

10
application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java

@ -161,20 +161,20 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
configurationDescriptor.set("nodeDefinition", node);
scannedComponent.setConfigurationDescriptor(configurationDescriptor);
scannedComponent.setClazz(clazzName);
log.info("Processing scanned component: {}", scannedComponent);
log.debug("Processing scanned component: {}", scannedComponent);
} catch (Exception e) {
log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e);
throw new RuntimeException(e);
}
ComponentDescriptor persistedComponent = componentDescriptorService.findByClazz(TenantId.SYS_TENANT_ID, clazzName);
if (persistedComponent == null) {
log.info("Persisting new component: {}", scannedComponent);
log.debug("Persisting new component: {}", scannedComponent);
scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent);
} else if (scannedComponent.equals(persistedComponent)) {
log.info("Component is already persisted: {}", persistedComponent);
log.debug("Component is already persisted: {}", persistedComponent);
scannedComponent = persistedComponent;
} else {
log.info("Component {} will be updated to {}", persistedComponent, scannedComponent);
log.debug("Component {} will be updated to {}", persistedComponent, scannedComponent);
componentDescriptorService.deleteByClazz(TenantId.SYS_TENANT_ID, persistedComponent.getClazz());
scannedComponent.setId(persistedComponent.getId());
scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent);
@ -224,7 +224,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
@Override
public void discoverComponents() {
registerRuleNodeComponents();
log.info("Found following definitions: {}", components.values());
log.debug("Found following definitions: {}", components.values());
}
@Override

71
application/src/main/java/org/thingsboard/server/service/device/ClaimDevicesServiceImpl.java

@ -28,6 +28,7 @@ import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Customer;
@ -52,12 +53,10 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.common.data.CacheConstants.CLAIM_DEVICES_CACHE;
@ -122,55 +121,57 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
}, MoreExecutors.directExecutor());
}
private ClaimDataInfo getClaimData(Cache cache, Device device) throws ExecutionException, InterruptedException {
private ListenableFuture<ClaimDataInfo> getClaimData(Cache cache, Device device) {
List<Object> key = constructCacheKey(device.getId());
ClaimData claimDataFromCache = cache.get(key, ClaimData.class);
if (claimDataFromCache != null) {
return new ClaimDataInfo(true, key, claimDataFromCache);
return Futures.immediateFuture(new ClaimDataInfo(true, key, claimDataFromCache));
} else {
Optional<AttributeKvEntry> claimDataAttr = attributesService.find(device.getTenantId(), device.getId(),
DataConstants.SERVER_SCOPE, CLAIM_DATA_ATTRIBUTE_NAME).get();
if (claimDataAttr.isPresent()) {
try {
ClaimData claimDataFromAttribute = mapper.readValue(claimDataAttr.get().getValueAsString(), ClaimData.class);
ListenableFuture<Optional<AttributeKvEntry>> claimDataAttrFuture = attributesService.find(device.getTenantId(), device.getId(),
DataConstants.SERVER_SCOPE, CLAIM_DATA_ATTRIBUTE_NAME);
return Futures.transform(claimDataAttrFuture, claimDataAttr -> {
if (claimDataAttr.isPresent()) {
ClaimData claimDataFromAttribute = JacksonUtil.fromString(claimDataAttr.get().getValueAsString(), ClaimData.class);
return new ClaimDataInfo(false, key, claimDataFromAttribute);
} catch (IOException e) {
log.warn("Failed to read Claim Data [{}] from attribute!", claimDataAttr, e);
}
}
return null;
}, MoreExecutors.directExecutor());
}
return null;
}
@Override
public ListenableFuture<ClaimResult> claimDevice(Device device, CustomerId customerId, String secretKey) throws ExecutionException, InterruptedException {
public ListenableFuture<ClaimResult> claimDevice(Device device, CustomerId customerId, String secretKey) {
Cache cache = cacheManager.getCache(CLAIM_DEVICES_CACHE);
ClaimDataInfo claimData = getClaimData(cache, device);
if (claimData != null) {
long currTs = System.currentTimeMillis();
if (currTs > claimData.getData().getExpirationTime() || !secretKeyIsEmptyOrEqual(secretKey, claimData.getData().getSecretKey())) {
log.warn("The claiming timeout occurred or wrong 'secretKey' provided for the device [{}]", device.getName());
if (claimData.isFromCache()) {
cache.evict(claimData.getKey());
ListenableFuture<ClaimDataInfo> claimDataFuture = getClaimData(cache, device);
return Futures.transformAsync(claimDataFuture, claimData -> {
if (claimData != null) {
long currTs = System.currentTimeMillis();
if (currTs > claimData.getData().getExpirationTime() || !secretKeyIsEmptyOrEqual(secretKey, claimData.getData().getSecretKey())) {
log.warn("The claiming timeout occurred or wrong 'secretKey' provided for the device [{}]", device.getName());
if (claimData.isFromCache()) {
cache.evict(claimData.getKey());
}
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
} else {
if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
device.setCustomerId(customerId);
Device savedDevice = deviceService.saveDevice(device);
clusterService.onDeviceUpdated(savedDevice, device);
return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS), MoreExecutors.directExecutor());
}
return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED), MoreExecutors.directExecutor());
}
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
} else {
log.warn("Failed to find the device's claiming message![{}]", device.getName());
if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
device.setCustomerId(customerId);
Device savedDevice = deviceService.saveDevice(device);
clusterService.onDeviceUpdated(savedDevice, device);
return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS), MoreExecutors.directExecutor());
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
} else {
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.CLAIMED));
}
return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED), MoreExecutors.directExecutor());
}
} else {
log.warn("Failed to find the device's claiming message![{}]", device.getName());
if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
} else {
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.CLAIMED));
}
}
}, MoreExecutors.directExecutor());
}
private boolean secretKeyIsEmptyOrEqual(String secretKeyA, String secretKeyB) {

10
application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java

@ -49,9 +49,9 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.importing.AbstractBulkImportService;
import org.thingsboard.server.service.importing.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Collection;
@ -121,7 +121,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
}
entity.setDeviceProfileId(deviceProfile.getId());
return tbDeviceService.saveDeviceWithCredentials(user.getTenantId(), entity, deviceCredentials, user);
return tbDeviceService.saveDeviceWithCredentials(entity, deviceCredentials, user);
}
@Override
@ -176,7 +176,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode();
Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE,
BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE).stream()
BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE).stream()
.map(fields::get)
.filter(Objects::nonNull)
.forEach(securityMode -> {
@ -233,7 +233,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration();
transportConfiguration.setBootstrap(Collections.emptyList());
transportConfiguration.setClientLwM2mSettings(new OtherConfiguration(1,1,1, PowerMode.DRX, null, null, null, null, null));
transportConfiguration.setClientLwM2mSettings(new OtherConfiguration(1, 1, 1, PowerMode.DRX, null, null, null, null, null));
transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()));
DeviceProfileData deviceProfileData = new DeviceProfileData();

2
application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java

@ -137,6 +137,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case ENTITY_VIEW:
case DASHBOARD:
case RULE_CHAIN:
case OTA_PACKAGE:
future = entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case CUSTOMER:
@ -144,6 +145,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
break;
case WIDGETS_BUNDLE:
case WIDGET_TYPE:
case QUEUE:
future = entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
break;
case ALARM:

4
application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java

@ -28,9 +28,9 @@ import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.importing.AbstractBulkImportService;
import org.thingsboard.server.service.importing.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Map;

16
application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java

@ -26,6 +26,8 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService;
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.user.UserService;
@ -41,6 +43,8 @@ import org.thingsboard.server.service.edge.rpc.processor.DeviceEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.DeviceProfileEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.EntityEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.EntityViewEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.OtaPackageEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.QueueEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.RelationEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.RuleChainEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.TelemetryEdgeProcessor;
@ -93,6 +97,12 @@ public class EdgeContextComponent {
@Autowired
private EdgeRequestsService edgeRequestsService;
@Autowired
private OtaPackageService otaPackageService;
@Autowired
private QueueService queueService;
@Autowired
private AlarmEdgeProcessor alarmProcessor;
@ -138,6 +148,12 @@ public class EdgeContextComponent {
@Autowired
private AdminSettingsEdgeProcessor adminSettingsProcessor;
@Autowired
private OtaPackageEdgeProcessor otaPackageEdgeProcessor;
@Autowired
private QueueEdgeProcessor queueEdgeProcessor;
@Autowired
private EdgeEventStorageSettings edgeEventStorageSettings;

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -536,6 +536,10 @@ public final class EdgeGrpcSession implements Closeable {
return ctx.getWidgetTypeProcessor().processWidgetTypeToEdge(edgeEvent, msgType, action);
case ADMIN_SETTINGS:
return ctx.getAdminSettingsProcessor().processAdminSettingsToEdge(edgeEvent);
case OTA_PACKAGE:
return ctx.getOtaPackageEdgeProcessor().processOtaPackageToEdge(edgeEvent, msgType, action);
case QUEUE:
return ctx.getQueueEdgeProcessor().processQueueToEdge(edgeEvent, msgType, action);
default:
log.warn("Unsupported edge event type [{}]", edgeEvent);
return null;

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java

@ -25,6 +25,8 @@ import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetch
import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.EdgeEventFetcher;
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.SystemWidgetsBundlesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.TenantAdminUsersEdgeEventFetcher;
@ -41,6 +43,7 @@ public class EdgeSyncCursor {
int currentIdx = 0;
public EdgeSyncCursor(EdgeContextComponent ctx, Edge edge) {
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()));
@ -53,6 +56,7 @@ public class EdgeSyncCursor {
fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
fetchers.add(new OtaPackagesEdgeEventFetcher(ctx.getOtaPackageService()));
}
public boolean hasNext() {

8
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java

@ -20,7 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -48,9 +48,9 @@ public class DeviceProfileMsgConstructor {
// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());
// }
// if (deviceProfile.getDefaultQueueName() != null) {
// builder.setDefaultQueueName(deviceProfile.getDefaultQueueName());
// }
if (deviceProfile.getDefaultQueueName() != null) {
builder.setDefaultQueueName(deviceProfile.getDefaultQueueName());
}
if (deviceProfile.getDescription() != null) {
builder.setDescription(deviceProfile.getDescription());
}

77
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/OtaPackageMsgConstructor.java

@ -0,0 +1,77 @@
/**
* Copyright © 2016-2022 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.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
@Component
@TbCoreComponent
public class OtaPackageMsgConstructor {
public OtaPackageUpdateMsg constructOtaPackageUpdatedMsg(UpdateMsgType msgType, OtaPackage otaPackage) {
OtaPackageUpdateMsg.Builder builder = OtaPackageUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(otaPackage.getId().getId().getMostSignificantBits())
.setIdLSB(otaPackage.getId().getId().getLeastSignificantBits())
.setDeviceProfileIdMSB(otaPackage.getDeviceProfileId().getId().getMostSignificantBits())
.setDeviceProfileIdLSB(otaPackage.getDeviceProfileId().getId().getLeastSignificantBits())
.setType(otaPackage.getType().name())
.setTitle(otaPackage.getTitle())
.setVersion(otaPackage.getVersion())
.setTag(otaPackage.getTag());
if (otaPackage.getUrl() != null) {
builder.setUrl(otaPackage.getUrl());
}
if (otaPackage.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(otaPackage.getAdditionalInfo()));
}
if (otaPackage.getFileName() != null) {
builder.setFileName(otaPackage.getFileName());
}
if (otaPackage.getContentType() != null) {
builder.setContentType(otaPackage.getContentType());
}
if (otaPackage.getChecksumAlgorithm() != null) {
builder.setChecksumAlgorithm(otaPackage.getChecksumAlgorithm().name());
}
if (otaPackage.getChecksum() != null) {
builder.setChecksum(otaPackage.getChecksum());
}
if (otaPackage.getDataSize() != null) {
builder.setDataSize(otaPackage.getDataSize());
}
if (otaPackage.getData() != null) {
builder.setData(ByteString.copyFrom(otaPackage.getData().array()));
}
return builder.build();
}
public OtaPackageUpdateMsg constructOtaPackageDeleteMsg(OtaPackageId otaPackageId) {
return OtaPackageUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(otaPackageId.getId().getMostSignificantBits())
.setIdLSB(otaPackageId.getId().getLeastSignificantBits()).build();
}
}

75
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/QueueMsgConstructor.java

@ -0,0 +1,75 @@
/**
* Copyright © 2016-2022 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.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.queue.ProcessingStrategy;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.queue.SubmitStrategy;
import org.thingsboard.server.gen.edge.v1.ProcessingStrategyProto;
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.SubmitStrategyProto;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
@Component
@TbCoreComponent
public class QueueMsgConstructor {
public QueueUpdateMsg constructQueueUpdatedMsg(UpdateMsgType msgType, Queue queue) {
QueueUpdateMsg.Builder builder = QueueUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(queue.getId().getId().getMostSignificantBits())
.setIdLSB(queue.getId().getId().getLeastSignificantBits())
.setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits())
.setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits())
.setName(queue.getName())
.setTopic(queue.getTopic())
.setPollInterval(queue.getPollInterval())
.setPartitions(queue.getPartitions())
.setConsumerPerPartition(queue.isConsumerPerPartition())
.setPackProcessingTimeout(queue.getPackProcessingTimeout())
.setSubmitStrategy(createSubmitStrategyProto(queue.getSubmitStrategy()))
.setProcessingStrategy(createProcessingStrategyProto(queue.getProcessingStrategy()));
return builder.build();
}
private ProcessingStrategyProto createProcessingStrategyProto(ProcessingStrategy processingStrategy) {
return ProcessingStrategyProto.newBuilder()
.setType(processingStrategy.getType().name())
.setRetries(processingStrategy.getRetries())
.setFailurePercentage(processingStrategy.getFailurePercentage())
.setPauseBetweenRetries(processingStrategy.getPauseBetweenRetries())
.setMaxPauseBetweenRetries(processingStrategy.getMaxPauseBetweenRetries())
.build();
}
private SubmitStrategyProto createSubmitStrategyProto(SubmitStrategy submitStrategy) {
return SubmitStrategyProto.newBuilder()
.setType(submitStrategy.getType().name())
.setBatchSize(submitStrategy.getBatchSize())
.build();
}
public QueueUpdateMsg constructQueueDeleteMsg(QueueId queueId) {
return QueueUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(queueId.getId().getMostSignificantBits())
.setIdLSB(queueId.getId().getLeastSignificantBits()).build();
}
}

253
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java

@ -15,44 +15,26 @@
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleNodeProto;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadataConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadataConstructorFactory;
@Component
@Slf4j
@TbCoreComponent
public class RuleChainMsgConstructor {
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final String RULE_CHAIN_INPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainInputNode";
private static final String TB_RULE_CHAIN_OUTPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainOutputNode";
public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
.setMsgType(msgType)
@ -69,231 +51,13 @@ public class RuleChainMsgConstructor {
return builder.build();
}
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType,
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
UpdateMsgType msgType,
RuleChainMetaData ruleChainMetaData,
EdgeVersion edgeVersion) {
try {
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder();
switch (edgeVersion) {
case V_3_3_0:
constructRuleChainMetadataUpdatedMsg_V_3_3_0(builder, ruleChainMetaData);
break;
case V_3_3_3:
default:
constructRuleChainMetadataUpdatedMsg_V_3_3_3(builder, ruleChainMetaData);
break;
}
builder.setMsgType(msgType);
return builder.build();
} catch (JsonProcessingException ex) {
log.error("Can't construct RuleChainMetadataUpdateMsg", ex);
}
return null;
}
private void constructRuleChainMetadataUpdatedMsg_V_3_3_3(RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
builder.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits())
.setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits())
.addAllNodes(constructNodes(ruleChainMetaData.getNodes()))
.addAllConnections(constructConnections(ruleChainMetaData.getConnections()))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections(), new TreeSet<>()));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
} else {
builder.setFirstNodeIndex(-1);
}
}
private void constructRuleChainMetadataUpdatedMsg_V_3_3_0(RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
List<RuleNode> supportedNodes = filterNodes_V_3_3_0(ruleChainMetaData.getNodes());
NavigableSet<Integer> removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections());
List<NodeConnectionInfo> connections = filterConnections_V_3_3_0(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes);
List<RuleChainConnectionInfo> ruleChainConnections = new ArrayList<>();
if (ruleChainMetaData.getRuleChainConnections() != null) {
ruleChainConnections.addAll(ruleChainMetaData.getRuleChainConnections());
}
ruleChainConnections.addAll(addRuleChainConnections_V_3_3_0(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections()));
builder.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits())
.setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits())
.addAllNodes(constructNodes(supportedNodes))
.addAllConnections(constructConnections(connections))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainConnections, removedNodeIndexes));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
Integer firstNodeIndex = ruleChainMetaData.getFirstNodeIndex();
// decrease index because of removed nodes
for (Integer removedIndex : removedNodeIndexes) {
if (firstNodeIndex > removedIndex) {
firstNodeIndex = firstNodeIndex - 1;
}
}
builder.setFirstNodeIndex(firstNodeIndex);
} else {
builder.setFirstNodeIndex(-1);
}
}
private List<NodeConnectionInfo> filterConnections_V_3_3_0(List<RuleNode> nodes, List<NodeConnectionInfo> connections, NavigableSet<Integer> removedNodeIndexes) {
List<NodeConnectionInfo> result = new ArrayList<>();
if (connections != null) {
result = connections.stream().filter(conn -> {
for (int i = 0; i < nodes.size(); i++) {
RuleNode node = nodes.get(i);
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)
|| node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) {
if (conn.getFromIndex() == i || conn.getToIndex() == i) {
return false;
}
}
}
return true;
}).map(conn -> {
NodeConnectionInfo newConn = new NodeConnectionInfo();
newConn.setFromIndex(conn.getFromIndex());
newConn.setToIndex(conn.getToIndex());
newConn.setType(conn.getType());
return newConn;
}).collect(Collectors.toList());
}
// decrease index because of removed nodes
for (Integer removedIndex : removedNodeIndexes) {
for (NodeConnectionInfo newConn : result) {
if (newConn.getToIndex() > removedIndex) {
newConn.setToIndex(newConn.getToIndex() - 1);
}
if (newConn.getFromIndex() > removedIndex) {
newConn.setFromIndex(newConn.getFromIndex() - 1);
}
}
}
return result;
}
private NavigableSet<Integer> getRemovedNodeIndexes(List<RuleNode> nodes, List<NodeConnectionInfo> connections) {
TreeSet<Integer> removedIndexes = new TreeSet<>();
for (NodeConnectionInfo connection : connections) {
for (int i = 0; i < nodes.size(); i++) {
RuleNode node = nodes.get(i);
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)
|| node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) {
if (connection.getFromIndex() == i || connection.getToIndex() == i) {
removedIndexes.add(i);
}
}
}
}
return removedIndexes.descendingSet();
}
private List<NodeConnectionInfoProto> constructConnections(List<NodeConnectionInfo> connections) {
List<NodeConnectionInfoProto> result = new ArrayList<>();
if (connections != null && !connections.isEmpty()) {
for (NodeConnectionInfo connection : connections) {
result.add(constructConnection(connection));
}
}
return result;
}
private NodeConnectionInfoProto constructConnection(NodeConnectionInfo connection) {
return NodeConnectionInfoProto.newBuilder()
.setFromIndex(connection.getFromIndex())
.setToIndex(connection.getToIndex())
.setType(connection.getType())
.build();
}
private List<RuleNode> filterNodes_V_3_3_0(List<RuleNode> nodes) {
List<RuleNode> result = new ArrayList<>();
for (RuleNode node : nodes) {
switch (node.getType()) {
case RULE_CHAIN_INPUT_NODE:
case TB_RULE_CHAIN_OUTPUT_NODE:
log.trace("Skipping not supported rule node {}", node);
break;
default:
result.add(node);
}
}
return result;
}
private List<RuleNodeProto> constructNodes(List<RuleNode> nodes) throws JsonProcessingException {
List<RuleNodeProto> result = new ArrayList<>();
if (nodes != null && !nodes.isEmpty()) {
for (RuleNode node : nodes) {
result.add(constructNode(node));
}
}
return result;
}
private List<RuleChainConnectionInfo> addRuleChainConnections_V_3_3_0(List<RuleNode> nodes, List<NodeConnectionInfo> connections) throws JsonProcessingException {
List<RuleChainConnectionInfo> result = new ArrayList<>();
for (int i = 0; i < nodes.size(); i++) {
RuleNode node = nodes.get(i);
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)) {
for (NodeConnectionInfo connection : connections) {
if (connection.getToIndex() == i) {
RuleChainConnectionInfo e = new RuleChainConnectionInfo();
e.setFromIndex(connection.getFromIndex());
TbRuleChainInputNodeConfiguration configuration = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainInputNodeConfiguration.class);
e.setTargetRuleChainId(new RuleChainId(UUID.fromString(configuration.getRuleChainId())));
e.setAdditionalInfo(node.getAdditionalInfo());
e.setType(connection.getType());
result.add(e);
}
}
}
}
return result;
}
private List<RuleChainConnectionInfoProto> constructRuleChainConnections(List<RuleChainConnectionInfo> ruleChainConnections, NavigableSet<Integer> removedNodeIndexes) throws JsonProcessingException {
List<RuleChainConnectionInfoProto> result = new ArrayList<>();
if (ruleChainConnections != null && !ruleChainConnections.isEmpty()) {
for (RuleChainConnectionInfo ruleChainConnectionInfo : ruleChainConnections) {
result.add(constructRuleChainConnection(ruleChainConnectionInfo, removedNodeIndexes));
}
}
return result;
}
private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo, NavigableSet<Integer> removedNodeIndexes) throws JsonProcessingException {
int fromIndex = ruleChainConnectionInfo.getFromIndex();
// decrease index because of removed nodes
for (Integer removedIndex : removedNodeIndexes) {
if (fromIndex > removedIndex) {
fromIndex = fromIndex - 1;
}
}
ObjectNode additionalInfo = (ObjectNode) ruleChainConnectionInfo.getAdditionalInfo();
if (additionalInfo.get("ruleChainNodeId") == null) {
additionalInfo.put("ruleChainNodeId", "rule-chain-node-UNDEFINED");
}
return RuleChainConnectionInfoProto.newBuilder()
.setFromIndex(fromIndex)
.setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits())
.setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits())
.setType(ruleChainConnectionInfo.getType())
.setAdditionalInfo(objectMapper.writeValueAsString(additionalInfo))
.build();
}
private RuleNodeProto constructNode(RuleNode node) throws JsonProcessingException {
return RuleNodeProto.newBuilder()
.setIdMSB(node.getId().getId().getMostSignificantBits())
.setIdLSB(node.getId().getId().getLeastSignificantBits())
.setType(node.getType())
.setName(node.getName())
.setDebugMode(node.isDebugMode())
.setConfiguration(objectMapper.writeValueAsString(node.getConfiguration()))
.setAdditionalInfo(objectMapper.writeValueAsString(node.getAdditionalInfo()))
.build();
RuleChainMetadataConstructor ruleChainMetadataConstructor
= RuleChainMetadataConstructorFactory.getByEdgeVersion(edgeVersion);
return ruleChainMetadataConstructor.constructRuleChainMetadataUpdatedMsg(tenantId, msgType, ruleChainMetaData);
}
public RuleChainUpdateMsg constructRuleChainDeleteMsg(RuleChainId ruleChainId) {
@ -302,5 +66,4 @@ public class RuleChainMsgConstructor {
.setIdMSB(ruleChainId.getId().getMostSignificantBits())
.setIdLSB(ruleChainId.getId().getLeastSignificantBits()).build();
}
}

137
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java

@ -0,0 +1,137 @@
/**
* Copyright © 2016-2022 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.rule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleNodeProto;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
@Slf4j
@AllArgsConstructor
public abstract class AbstractRuleChainMetadataConstructor implements RuleChainMetadataConstructor {
@Override
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
UpdateMsgType msgType,
RuleChainMetaData ruleChainMetaData) {
try {
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder();
builder.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits())
.setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits());
constructRuleChainMetadataUpdatedMsg(tenantId, builder, ruleChainMetaData);
builder.setMsgType(msgType);
return builder.build();
} catch (JsonProcessingException ex) {
log.error("Can't construct RuleChainMetadataUpdateMsg", ex);
}
return null;
}
protected abstract void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException;
protected List<NodeConnectionInfoProto> constructConnections(List<NodeConnectionInfo> connections) {
List<NodeConnectionInfoProto> result = new ArrayList<>();
if (connections != null && !connections.isEmpty()) {
for (NodeConnectionInfo connection : connections) {
result.add(constructConnection(connection));
}
}
return result;
}
private NodeConnectionInfoProto constructConnection(NodeConnectionInfo connection) {
return NodeConnectionInfoProto.newBuilder()
.setFromIndex(connection.getFromIndex())
.setToIndex(connection.getToIndex())
.setType(connection.getType())
.build();
}
protected List<RuleNodeProto> constructNodes(List<RuleNode> nodes) throws JsonProcessingException {
List<RuleNodeProto> result = new ArrayList<>();
if (nodes != null && !nodes.isEmpty()) {
for (RuleNode node : nodes) {
result.add(constructNode(node));
}
}
return result;
}
private RuleNodeProto constructNode(RuleNode node) throws JsonProcessingException {
return RuleNodeProto.newBuilder()
.setIdMSB(node.getId().getId().getMostSignificantBits())
.setIdLSB(node.getId().getId().getLeastSignificantBits())
.setType(node.getType())
.setName(node.getName())
.setDebugMode(node.isDebugMode())
.setConfiguration(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getConfiguration()))
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getAdditionalInfo()))
.build();
}
protected List<RuleChainConnectionInfoProto> constructRuleChainConnections(List<RuleChainConnectionInfo> ruleChainConnections,
NavigableSet<Integer> removedNodeIndexes) throws JsonProcessingException {
List<RuleChainConnectionInfoProto> result = new ArrayList<>();
if (ruleChainConnections != null && !ruleChainConnections.isEmpty()) {
for (RuleChainConnectionInfo ruleChainConnectionInfo : ruleChainConnections) {
if (!removedNodeIndexes.isEmpty()) { // 3_3_0 only
int fromIndex = ruleChainConnectionInfo.getFromIndex();
// decrease index because of removed nodes
for (Integer removedIndex : removedNodeIndexes) {
if (fromIndex > removedIndex) {
fromIndex = fromIndex - 1;
}
}
ruleChainConnectionInfo.setFromIndex(fromIndex);
ObjectNode additionalInfo = (ObjectNode) ruleChainConnectionInfo.getAdditionalInfo();
if (additionalInfo.get("ruleChainNodeId") == null) {
additionalInfo.put("ruleChainNodeId", "rule-chain-node-UNDEFINED");
}
}
result.add(constructRuleChainConnection(ruleChainConnectionInfo));
}
}
return result;
}
private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo) throws JsonProcessingException {
return RuleChainConnectionInfoProto.newBuilder()
.setFromIndex(ruleChainConnectionInfo.getFromIndex())
.setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits())
.setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits())
.setType(ruleChainConnectionInfo.getType())
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo()))
.build();
}
}

28
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructor.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2022 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.rule;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
public interface RuleChainMetadataConstructor {
RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
UpdateMsgType msgType,
RuleChainMetaData ruleChainMetaData);
}

32
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java

@ -0,0 +1,32 @@
/**
* Copyright © 2016-2022 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.rule;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
public final class RuleChainMetadataConstructorFactory {
public static RuleChainMetadataConstructor getByEdgeVersion(EdgeVersion edgeVersion) {
switch (edgeVersion) {
case V_3_3_0:
return new RuleChainMetadataConstructorV330();
case V_3_3_3:
case V_3_4_0:
default:
return new RuleChainMetadataConstructorV340();
}
}
}

165
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java

@ -0,0 +1,165 @@
/**
* Copyright © 2016-2022 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.rule;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
@Slf4j
public class RuleChainMetadataConstructorV330 extends AbstractRuleChainMetadataConstructor {
private static final String RULE_CHAIN_INPUT_NODE = TbRuleChainInputNode.class.getName();
private static final String TB_RULE_CHAIN_OUTPUT_NODE = TbRuleChainOutputNode.class.getName();
@Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
List<RuleNode> supportedNodes = filterNodes(ruleChainMetaData.getNodes());
NavigableSet<Integer> removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections());
List<NodeConnectionInfo> connections = filterConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes);
List<RuleChainConnectionInfo> ruleChainConnections = new ArrayList<>();
if (ruleChainMetaData.getRuleChainConnections() != null) {
ruleChainConnections.addAll(ruleChainMetaData.getRuleChainConnections());
}
ruleChainConnections.addAll(addRuleChainConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections()));
builder.addAllNodes(constructNodes(supportedNodes))
.addAllConnections(constructConnections(connections))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainConnections, removedNodeIndexes));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
Integer firstNodeIndex = ruleChainMetaData.getFirstNodeIndex();
// decrease index because of removed nodes
for (Integer removedIndex : removedNodeIndexes) {
if (firstNodeIndex > removedIndex) {
firstNodeIndex = firstNodeIndex - 1;
}
}
builder.setFirstNodeIndex(firstNodeIndex);
} else {
builder.setFirstNodeIndex(-1);
}
}
private NavigableSet<Integer> getRemovedNodeIndexes(List<RuleNode> nodes, List<NodeConnectionInfo> connections) {
TreeSet<Integer> removedIndexes = new TreeSet<>();
for (NodeConnectionInfo connection : connections) {
for (int i = 0; i < nodes.size(); i++) {
RuleNode node = nodes.get(i);
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)
|| node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) {
if (connection.getFromIndex() == i || connection.getToIndex() == i) {
removedIndexes.add(i);
}
}
}
}
return removedIndexes.descendingSet();
}
private List<NodeConnectionInfo> filterConnections(List<RuleNode> nodes,
List<NodeConnectionInfo> connections,
NavigableSet<Integer> removedNodeIndexes) {
List<NodeConnectionInfo> result = new ArrayList<>();
if (connections != null) {
result = connections.stream().filter(conn -> {
for (int i = 0; i < nodes.size(); i++) {
RuleNode node = nodes.get(i);
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)
|| node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) {
if (conn.getFromIndex() == i || conn.getToIndex() == i) {
return false;
}
}
}
return true;
}).map(conn -> {
NodeConnectionInfo newConn = new NodeConnectionInfo();
newConn.setFromIndex(conn.getFromIndex());
newConn.setToIndex(conn.getToIndex());
newConn.setType(conn.getType());
return newConn;
}).collect(Collectors.toList());
}
// decrease index because of removed nodes
for (Integer removedIndex : removedNodeIndexes) {
for (NodeConnectionInfo newConn : result) {
if (newConn.getToIndex() > removedIndex) {
newConn.setToIndex(newConn.getToIndex() - 1);
}
if (newConn.getFromIndex() > removedIndex) {
newConn.setFromIndex(newConn.getFromIndex() - 1);
}
}
}
return result;
}
private List<RuleNode> filterNodes(List<RuleNode> nodes) {
List<RuleNode> result = new ArrayList<>();
for (RuleNode node : nodes) {
if (RULE_CHAIN_INPUT_NODE.equals(node.getType())
|| TB_RULE_CHAIN_OUTPUT_NODE.equals(node.getType())) {
log.trace("Skipping not supported rule node {}", node);
} else {
result.add(node);
}
}
return result;
}
private List<RuleChainConnectionInfo> addRuleChainConnections(List<RuleNode> nodes, List<NodeConnectionInfo> connections) {
List<RuleChainConnectionInfo> result = new ArrayList<>();
for (int i = 0; i < nodes.size(); i++) {
RuleNode node = nodes.get(i);
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)) {
for (NodeConnectionInfo connection : connections) {
if (connection.getToIndex() == i) {
RuleChainConnectionInfo e = new RuleChainConnectionInfo();
e.setFromIndex(connection.getFromIndex());
TbRuleChainInputNodeConfiguration configuration = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainInputNodeConfiguration.class);
e.setTargetRuleChainId(new RuleChainId(UUID.fromString(configuration.getRuleChainId())));
e.setAdditionalInfo(node.getAdditionalInfo());
e.setType(connection.getType());
result.add(e);
}
}
}
}
return result;
}
}

42
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2022 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.rule;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.TreeSet;
@Slf4j
public class RuleChainMetadataConstructorV340 extends AbstractRuleChainMetadataConstructor {
@Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
builder.addAllNodes(constructNodes(ruleChainMetaData.getNodes()))
.addAllConnections(constructConnections(ruleChainMetaData.getConnections()))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections(), new TreeSet<>()));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
} else {
builder.setFirstNodeIndex(-1);
}
}
}

7
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java

@ -83,7 +83,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)));
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
AdminSettings tenantMailSettings = convertToTenantAdminSettings(tenantId, systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)));
@ -91,7 +91,7 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)));
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(tenantId, systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)));
@ -151,8 +151,9 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
}
}
private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
private AdminSettings convertToTenantAdminSettings(TenantId tenantId, String key, ObjectNode jsonValue) {
AdminSettings tenantMailSettings = new AdminSettings();
tenantMailSettings.setTenantId(tenantId);
jsonValue.put("useSystemMailSettings", true);
tenantMailSettings.setJsonValue(jsonValue);
tenantMailSettings.setKey(key);

47
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OtaPackagesEdgeEventFetcher.java

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2022 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.OtaPackageInfo;
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.ota.OtaPackageService;
@AllArgsConstructor
@Slf4j
public class OtaPackagesEdgeEventFetcher extends BasePageableEdgeEventFetcher<OtaPackageInfo> {
private final OtaPackageService otaPackageService;
@Override
PageData<OtaPackageInfo> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) {
return otaPackageService.findTenantOtaPackagesByTenantId(tenantId, pageLink);
}
@Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, OtaPackageInfo otaPackageInfo) {
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.OTA_PACKAGE,
EdgeEventActionType.ADDED, otaPackageInfo.getId(), null);
}
}

47
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/QueuesEdgeEventFetcher.java

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2022 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.queue.Queue;
import org.thingsboard.server.dao.queue.QueueService;
@AllArgsConstructor
@Slf4j
public class QueuesEdgeEventFetcher extends BasePageableEdgeEventFetcher<Queue> {
private final QueueService queueService;
@Override
PageData<Queue> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) {
return queueService.findQueuesByTenantId(tenantId, pageLink);
}
@Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Queue queue) {
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.QUEUE,
EdgeEventActionType.ADDED, queue.getId(), null);
}
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetsBundlesEdgeEventFetcher.java

@ -32,6 +32,6 @@ public class TenantWidgetsBundlesEdgeEventFetcher extends BaseWidgetsBundlesEdge
}
@Override
protected PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink) {
return widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink);
return widgetsBundleService.findTenantWidgetsBundlesByTenantId(tenantId, pageLink);
}
}

50
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils;
@ -46,12 +47,17 @@ 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.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.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.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.service.edge.rpc.constructor.AdminSettingsMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AlarmMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AssetMsgConstructor;
@ -61,6 +67,8 @@ import org.thingsboard.server.service.edge.rpc.constructor.DeviceMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceProfileMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityDataMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityViewMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.OtaPackageMsgConstructor;
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.UserMsgConstructor;
@ -101,6 +109,9 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected EntityViewService entityViewService;
@Autowired
protected TenantService tenantService;
@Autowired
protected EdgeService edgeService;
@ -137,6 +148,19 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected WidgetTypeService widgetTypeService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected QueueService queueService;
@Autowired
protected PartitionService partitionService;
@Autowired
@Lazy
protected TbQueueProducerProvider producerProvider;
@Autowired
protected DataValidator<Device> deviceValidator;
@ -182,6 +206,12 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected AdminSettingsMsgConstructor adminSettingsMsgConstructor;
@Autowired
protected OtaPackageMsgConstructor otaPackageMsgConstructor;
@Autowired
protected QueueMsgConstructor queueMsgConstructor;
@Autowired
protected DbCallbackExecutorService dbCallbackExecutorService;
@ -212,6 +242,24 @@ public abstract class BaseEdgeProcessor {
}
protected ListenableFuture<Void> processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<TenantId> tenantsIds;
do {
tenantsIds = tenantService.findTenantsIds(pageLink);
for (TenantId tenantId1 : tenantsIds.getData()) {
futures.addAll(processActionForAllEdgesByTenantId(tenantId1, type, actionType, entityId));
}
pageLink = pageLink.nextPageLink();
} while (tenantsIds.hasNext());
} else {
futures = processActionForAllEdgesByTenantId(tenantId, type, actionType, entityId);
}
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
private List<ListenableFuture<Void>> processActionForAllEdgesByTenantId(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Edge> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
@ -226,6 +274,6 @@ public abstract class BaseEdgeProcessor {
}
}
} while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
return futures;
}
}

63
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/OtaPackageEdgeProcessor.java

@ -0,0 +1,63 @@
/**
* Copyright © 2016-2022 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;
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.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.OtaPackageId;
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.queue.util.TbCoreComponent;
@Component
@Slf4j
@TbCoreComponent
public class OtaPackageEdgeProcessor extends BaseEdgeProcessor {
public DownlinkMsg processOtaPackageToEdge(EdgeEvent edgeEvent, UpdateMsgType msgType, EdgeEventActionType action) {
OtaPackageId otaPackageId = new OtaPackageId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (action) {
case ADDED:
case UPDATED:
OtaPackage otaPackage = otaPackageService.findOtaPackageById(edgeEvent.getTenantId(), otaPackageId);
if (otaPackage != null) {
OtaPackageUpdateMsg otaPackageUpdateMsg =
otaPackageMsgConstructor.constructOtaPackageUpdatedMsg(msgType, otaPackage);
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOtaPackageUpdateMsg(otaPackageUpdateMsg)
.build();
}
break;
case DELETED:
OtaPackageUpdateMsg otaPackageUpdateMsg =
otaPackageMsgConstructor.constructOtaPackageDeleteMsg(otaPackageId);
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOtaPackageUpdateMsg(otaPackageUpdateMsg)
.build();
break;
}
return downlinkMsg;
}
}

63
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/QueueEdgeProcessor.java

@ -0,0 +1,63 @@
/**
* Copyright © 2016-2022 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;
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.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.QueueId;
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.queue.util.TbCoreComponent;
@Component
@Slf4j
@TbCoreComponent
public class QueueEdgeProcessor extends BaseEdgeProcessor {
public DownlinkMsg processQueueToEdge(EdgeEvent edgeEvent, UpdateMsgType msgType, EdgeEventActionType action) {
QueueId queueId = new QueueId(edgeEvent.getEntityId());
DownlinkMsg downlinkMsg = null;
switch (action) {
case ADDED:
case UPDATED:
Queue queue = queueService.findQueueById(edgeEvent.getTenantId(), queueId);
if (queue != null) {
QueueUpdateMsg queueUpdateMsg =
queueMsgConstructor.constructQueueUpdatedMsg(msgType, queue);
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addQueueUpdateMsg(queueUpdateMsg)
.build();
}
break;
case DELETED:
QueueUpdateMsg queueDeleteMsg =
queueMsgConstructor.constructQueueDeleteMsg(queueId);
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addQueueUpdateMsg(queueDeleteMsg)
.build();
break;
}
return downlinkMsg;
}
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RuleChainEdgeProcessor.java

@ -71,7 +71,7 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor {
if (ruleChain != null) {
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
ruleChainMsgConstructor.constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData, edgeVersion);
ruleChainMsgConstructor.constructRuleChainMetadataUpdatedMsg(edgeEvent.getTenantId(), msgType, ruleChainMetaData, edgeVersion);
if (ruleChainMetadataUpdateMsg != null) {
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())

58
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java

@ -52,6 +52,8 @@ import org.thingsboard.server.common.data.kv.AttributeKey;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.util.JsonUtils;
@ -61,9 +63,12 @@ import org.thingsboard.server.gen.edge.v1.EntityDataProto;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.TbQueueProducer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -77,14 +82,19 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
private final Gson gson = new Gson();
private TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> tbCoreMsgProducer;
@PostConstruct
public void init() {
tbCoreMsgProducer = producerProvider.getTbCoreMsgProducer();
}
public List<ListenableFuture<Void>> processTelemetryFromEdge(TenantId tenantId, CustomerId customerId, EntityDataProto entityData) {
log.trace("[{}] onTelemetryUpdate [{}]", tenantId, entityData);
List<ListenableFuture<Void>> result = new ArrayList<>();
EntityId entityId = constructEntityId(entityData);
if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg() || entityData.hasAttributesUpdatedMsg()) && entityId != null) {
// @voba - in terms of performance we should not fetch device from DB by id
// TbMsgMetaData metaData = constructBaseMsgMetadata(tenantId, entityId);
TbMsgMetaData metaData = new TbMsgMetaData();
TbMsgMetaData metaData = constructBaseMsgMetadata(tenantId, entityId);
metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);
if (entityData.hasPostAttributesMsg()) {
result.add(processPostAttributes(tenantId, customerId, entityId, entityData.getPostAttributesMsg(), metaData));
@ -96,6 +106,20 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
if (entityData.hasPostTelemetryMsg()) {
result.add(processPostTelemetry(tenantId, customerId, entityId, entityData.getPostTelemetryMsg(), metaData));
}
if (EntityType.DEVICE.equals(entityId.getEntityType())) {
DeviceId deviceId = new DeviceId(entityId.getId());
TransportProtos.DeviceActivityProto deviceActivityMsg = TransportProtos.DeviceActivityProto.newBuilder()
.setTenantIdMSB(tenantId.getId().getMostSignificantBits())
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits())
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits())
.setLastActivityTime(System.currentTimeMillis()).build();
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId);
tbCoreMsgProducer.send(tpi, new TbProtoQueueMsg<>(deviceId.getId(),
TransportProtos.ToCoreMsg.newBuilder().setDeviceActivityMsg(deviceActivityMsg).build()), null);
}
}
if (entityData.hasAttributeDeleteMsg()) {
result.add(processAttributeDeleteMsg(tenantId, entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType()));
@ -134,21 +158,21 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
return metaData;
}
private Pair<QueueId, RuleChainId> getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) {
private Pair<String, RuleChainId> getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) {
if (EntityType.DEVICE.equals(entityId.getEntityType())) {
DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
RuleChainId ruleChainId;
QueueId queueId;
String queueName;
if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", entityId);
ruleChainId = null;
queueId = null;
queueName = null;
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
queueId = deviceProfile.getDefaultQueueId();
queueName = deviceProfile.getDefaultQueueName();
}
return new ImmutablePair<>(queueId, ruleChainId);
return new ImmutablePair<>(queueName, ruleChainId);
} else {
return new ImmutablePair<>(null, null);
}
@ -159,10 +183,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + "");
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey();
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
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);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@ -182,10 +204,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
private ListenableFuture<Void> processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
SettableFuture<Void> futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey();
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
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);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@ -209,10 +229,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List<String> keys) {
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey();
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {

24
application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java

@ -25,6 +25,7 @@ import com.google.common.util.concurrent.SettableFuture;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device;
@ -60,7 +61,6 @@ import org.thingsboard.server.dao.attributes.AttributesService;
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.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
@ -72,7 +72,10 @@ import org.thingsboard.server.gen.edge.v1.RelationRequestMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
import java.util.ArrayList;
import java.util.HashMap;
@ -81,6 +84,7 @@ import java.util.Map;
import java.util.UUID;
@Service
@TbCoreComponent
@Slf4j
public class DefaultEdgeRequestsService implements EdgeRequestsService {
@ -100,8 +104,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Autowired
private DeviceService deviceService;
@Lazy
@Autowired
private EntityViewService entityViewService;
private TbEntityViewService entityViewService;
@Autowired
private DeviceProfileService deviceProfileService;
@ -160,6 +165,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
Map<String, Object> entityData = new HashMap<>();
ObjectNode attributes = mapper.createObjectNode();
for (AttributeKvEntry attr : ssAttributes) {
if (DefaultDeviceStateService.PERSISTENT_ATTRIBUTES.contains(attr.getKey())) {
continue;
}
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
attributes.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
@ -378,7 +386,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
}
List<ListenableFuture<Void>> futures = new ArrayList<>();
for (EntityView entityView : entityViews) {
ListenableFuture<Boolean> future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),
ListenableFuture<Boolean> future = relationService.checkRelationAsync(tenantId, edge.getId(), entityView.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
futures.add(Futures.transformAsync(future, result -> {
if (Boolean.TRUE.equals(result)) {
@ -413,11 +421,11 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
}
private ListenableFuture<Void> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
EntityId entityId,
JsonNode body) {
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
EntityId entityId,
JsonNode body) {
log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);

148
application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java

@ -23,15 +23,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -40,42 +37,17 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageDataIterableByTenantIdEntityId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
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.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.install.InstallScripts;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.resource.TbResourceService;
import org.thingsboard.server.service.rule.TbRuleChainService;
import org.thingsboard.server.service.security.permission.AccessControlService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import javax.mail.MessagingException;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
@Slf4j
@ -92,64 +64,18 @@ public abstract class AbstractTbEntityService {
@Autowired
protected DbCallbackExecutorService dbExecutor;
@Autowired
@Autowired(required = false)
protected TbNotificationEntityService notificationEntityService;
@Autowired(required = false)
protected EdgeService edgeService;
@Autowired
protected AlarmService alarmService;
@Autowired
protected EntityActionService entityActionService;
@Autowired
protected DeviceService deviceService;
@Autowired
protected AssetService assetService;
@Autowired
protected DeviceCredentialsService deviceCredentialsService;
@Autowired
protected TenantService tenantService;
@Autowired
protected CustomerService customerService;
@Autowired
protected ClaimDevicesService claimDevicesService;
@Autowired
protected TbTenantProfileCache tenantProfileCache;
@Autowired
protected RuleChainService ruleChainService;
@Autowired
protected TbRuleChainService tbRuleChainService;
@Autowired
protected EdgeNotificationService edgeNotificationService;
@Autowired
protected QueueService queueService;
@Autowired
protected DashboardService dashboardService;
@Autowired
protected EntityViewService entityViewService;
@Autowired
protected TelemetrySubscriptionService tsSubService;
@Autowired
protected AttributesService attributesService;
@Autowired
protected AccessControlService accessControlService;
@Autowired
protected DeviceProfileService deviceProfileService;
@Autowired
protected TbClusterService tbClusterService;
@Autowired
protected OtaPackageStateService otaPackageStateService;
@Autowired
protected RelationService relationService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected InstallScripts installScripts;
@Autowired
protected UserService userService;
@Autowired
protected TbResourceService resourceService;
@Autowired
protected WidgetsBundleService widgetsBundleService;
@Autowired(required = false)
private EntitiesVersionControlService vcService;
protected ListenableFuture<Void> removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) {
ListenableFuture<PageData<AlarmInfo>> alarmsFuture =
@ -164,15 +90,6 @@ public abstract class AbstractTbEntityService {
}, dbExecutor);
}
protected <E extends HasName, I extends EntityId> void logEntityAction(User user, TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException {
if (user != null) {
entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo);
} else if (e == null) {
entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo);
}
}
protected <T> T checkNotNull(T reference) throws ThingsboardException {
return checkNotNull(reference, "Requested item wasn't found!");
}
@ -196,37 +113,6 @@ public abstract class AbstractTbEntityService {
}
}
protected ThingsboardException handleException(Exception exception) {
return handleException(exception, true);
}
protected ThingsboardException handleException(Exception exception, boolean logException) {
if (logException && logControllerErrorStackTrace) {
log.error("Error [{}]", exception.getMessage(), exception);
}
String cause = "";
if (exception.getCause() != null) {
cause = exception.getCause().getClass().getCanonicalName();
}
if (exception instanceof ThingsboardException) {
return (ThingsboardException) exception;
} else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException
|| exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) {
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else if (exception instanceof MessagingException) {
return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL);
} else {
return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL);
}
}
@SuppressWarnings("unchecked")
protected <I extends EntityId> I emptyId(EntityType entityType) {
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
}
protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {
if (!edgesEnabled) {
return null;
@ -242,4 +128,26 @@ public abstract class AbstractTbEntityService {
}
return result;
}
protected <I extends EntityId> I emptyId(EntityType entityType) {
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
}
protected ListenableFuture<UUID> autoCommit(User user, EntityId entityId) throws Exception {
if (vcService != null) {
return vcService.autoCommit(user, entityId);
} else {
// We do not support auto-commit for rule engine
return Futures.immediateFailedFuture(new RuntimeException("Operation not supported!"));
}
}
protected ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds) throws Exception {
if (vcService != null) {
return vcService.autoCommit(user, entityType, entityIds);
} else {
// We do not support auto-commit for rule engine
return Futures.immediateFailedFuture(new RuntimeException("Operation not supported!"));
}
}
}

166
application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java

@ -15,11 +15,10 @@
*/
package org.thingsboard.server.service.entitiy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
@ -27,6 +26,7 @@ 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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
@ -46,52 +46,74 @@ 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
@Slf4j
@Service
@TbCoreComponent
@RequiredArgsConstructor
public class DefaultTbNotificationEntityService implements TbNotificationEntityService {
private static final ObjectMapper json = new ObjectMapper();
private final EntityActionService entityActionService;
private final TbClusterService tbClusterService;
private final GatewayNotificationsService gatewayNotificationsService;
@Override
public <E extends HasName, I extends EntityId> void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, SecurityUser user, Exception e,
Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo);
public <I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, ActionType actionType,
User user, Exception e, Object... additionalInfo) {
logEntityAction(tenantId, entityId, null, null, actionType, user, e, additionalInfo);
}
@Override
public <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity,
ActionType actionType, User user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, null, actionType, user, null, additionalInfo);
}
@Override
public <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity,
ActionType actionType, User user, Exception e,
Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, null, actionType, user, e, additionalInfo);
}
@Override
public <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, User user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, null, additionalInfo);
}
@Override
public <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType,
User user, Exception e, Object... additionalInfo) {
if (user != null) {
entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo);
} else if (e == null) {
entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo);
}
}
@Override
public <E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType,
List<EdgeId> relatedEdgeIds,
SecurityUser user, Object... additionalInfo) {
User user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds);
}
public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId,
CustomerId customerId,
List<EdgeId> relatedEdgeIds,
SecurityUser user,
String body, Object... additionalInfo) {
@Override
public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId,
List<EdgeId> 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<EdgeId> relatedEdgeIds, SecurityUser user) {
public void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, List<EdgeId> relatedEdgeIds, User user) {
RuleChainId ruleChainId = ruleChain.getId();
logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, null, ruleChainId.toString());
if (RuleChainType.EDGE.equals(ruleChain.getType())) {
@ -102,19 +124,18 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override
public <I extends EntityId> void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType) {
sendEntityNotificationMsg(tenantId, entityId, edgeEventActionType);
}
}
@Override
public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
CustomerId customerId, E entity,
ActionType actionType,
EdgeEventActionType edgeActionType,
SecurityUser user, boolean sendToEdge,
User user, boolean sendToEdge,
Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
if (sendToEdge) {
sendEntityAssignToCustomerNotificationMsg(tenantId, entityId, customerId, edgeActionType);
sendEntityAssignToCustomerNotificationMsg(tenantId, entityId, customerId, edgeTypeByActionType(actionType));
}
}
@ -122,13 +143,13 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
CustomerId customerId, EdgeId edgeId,
E entity, ActionType actionType,
SecurityUser user, Object... additionalInfo) {
User user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeTypeByActionType(actionType));
}
@Override
public void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) {
public void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) {
tbClusterService.onTenantChange(tenant, null);
tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), event);
}
@ -142,14 +163,14 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override
public void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId,
Device device, Device oldDevice, ActionType actionType,
SecurityUser user, Object... additionalInfo) {
User user, Object... additionalInfo) {
tbClusterService.onDeviceUpdated(device, oldDevice);
logEntityAction(tenantId, deviceId, device, customerId, actionType, user, additionalInfo);
}
@Override
public void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
List<EdgeId> relatedEdgeIds, SecurityUser user, Object... additionalInfo) {
List<EdgeId> relatedEdgeIds, User user, Object... additionalInfo) {
gatewayNotificationsService.onDeviceDeleted(device);
tbClusterService.onDeviceDeleted(device, null);
@ -158,7 +179,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override
public void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
DeviceCredentials deviceCredentials, SecurityUser user) {
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);
@ -166,13 +187,15 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override
public void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId,
Device device, Tenant tenant, SecurityUser user, Object... additionalInfo) {
Device device, Tenant tenant, User user, Object... additionalInfo) {
logEntityAction(tenantId, deviceId, device, customerId, ActionType.ASSIGNED_TO_TENANT, user, additionalInfo);
pushAssignedFromNotification(tenant, newTenantId, device);
}
@Override
public <E extends HasName, I extends EntityId> void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, SecurityUser user, Object... additionalInfo) {
public <E extends HasName, I extends EntityId> 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);
@ -180,8 +203,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
}
@Override
public void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType,
SecurityUser user, Object... additionalInfo) {
public void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge,
ActionType actionType, User user, Object... additionalInfo) {
ComponentLifecycleEvent lifecycleEvent;
EdgeEventActionType edgeEventActionType = null;
switch (actionType) {
@ -216,69 +239,50 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
}
@Override
public void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo) {
public void notifyCreateOrUpdateAlarm(Alarm 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 <E extends HasName, I extends EntityId> void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId,
I entityId, E entity, SecurityUser user,
I entityId, E entity, User user,
ActionType actionType, boolean sendNotifyMsgToEdge, Exception e,
Object... additionalInfo) {
notifyEntity(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo);
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo);
if (sendNotifyMsgToEdge) {
sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType));
}
}
@Override
public void notifyCreateOrUpdateOrDeleteRelation(TenantId tenantId, CustomerId customerId,
EntityRelation relation, SecurityUser user,
ActionType actionType, Exception e,
Object... additionalInfo) {
notifyEntity(tenantId, relation.getFrom(), null, customerId, actionType, user, e, additionalInfo);
notifyEntity(tenantId, relation.getTo(), null, customerId, actionType, user, e, additionalInfo);
if (e == null) {
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) {
sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation),
EdgeEventType.RELATION, edgeTypeByActionType(actionType));
}
} catch (Exception e1) {
log.warn("Failed to push relation to core: {}", relation, e1);
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);
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
sendNotificationMsgToEdge(tenantId, null, null, JacksonUtil.toString(relation),
EdgeEventType.RELATION, edgeTypeByActionType(actionType));
}
}
}
private <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, SecurityUser user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, null, additionalInfo);
}
private <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, SecurityUser user, Exception e, Object... additionalInfo) {
if (user != null) {
entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo);
} else if (e == null) {
entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo);
} catch (Exception e) {
log.warn("Failed to push relation to core: {}", relation, e);
}
}
private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) {
sendNotificationMsgToEdgeService(tenantId, null, entityId, null, null, action);
sendNotificationMsgToEdge(tenantId, null, entityId, null, null, action);
}
private void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) {
try {
sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action);
sendNotificationMsgToEdge(tenantId, null, entityId, JacksonUtil.toString(customerId), null, action);
} catch (Exception e) {
log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e);
}
}
protected void sendAlarmDeleteNotificationMsg(TenantId tenantId, Alarm alarm, List<EdgeId> edgeIds, String body) {
private void sendAlarmDeleteNotificationMsg(TenantId tenantId, Alarm alarm, List<EdgeId> edgeIds, String body) {
try {
sendDeleteNotificationMsg(tenantId, alarm.getId(), edgeIds, body);
} catch (Exception e) {
@ -286,8 +290,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
}
}
protected <E extends HasName, I extends EntityId> void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity,
List<EdgeId> edgeIds) {
private <E extends HasName, I extends EntityId> void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, List<EdgeId> edgeIds) {
try {
sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null);
} catch (Exception e) {
@ -298,23 +301,25 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, String body) {
if (edgeIds != null && !edgeIds.isEmpty()) {
for (EdgeId edgeId : edgeIds) {
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED);
sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED);
}
}
}
private void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) {
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, action);
sendNotificationMsgToEdge(tenantId, edgeId, entityId, null, null, action);
}
private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action);
private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body,
EdgeEventType type, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, type, action);
}
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
String data = entityToStr(assignedDevice);
String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
if (data != null) {
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(),
assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
}
}
@ -326,15 +331,6 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
return metaData;
}
private <E extends HasName> String entityToStr(E entity) {
try {
return json.writeValueAsString(json.valueToTree(entity));
} catch (JsonProcessingException e) {
log.warn("[{}] Failed to convert entity to string!", entity, e);
}
return null;
}
public static EdgeEventActionType edgeTypeByActionType(ActionType actionType) {
switch (actionType) {
case ADDED:
@ -351,6 +347,10 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
return EdgeEventActionType.RELATION_ADD_OR_UPDATE;
case RELATION_DELETED:
return EdgeEventActionType.RELATION_DELETED;
case ASSIGNED_TO_CUSTOMER:
return EdgeEventActionType.ASSIGNED_TO_CUSTOMER;
case UNASSIGNED_FROM_CUSTOMER:
return EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER;
case ASSIGNED_TO_EDGE:
return EdgeEventActionType.ASSIGNED_TO_EDGE;
case UNASSIGNED_FROM_EDGE:

11
application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java

@ -15,13 +15,16 @@
*/
package org.thingsboard.server.service.entitiy;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.User;
public interface SimpleTbEntityService<T> {
T save(T entity, SecurityUser user) throws ThingsboardException;
default T save(T entity) throws Exception {
return save(entity, null);
}
void delete (T entity, SecurityUser user) throws ThingsboardException;
T save(T entity, User user) throws Exception;
void delete(T entity, User user);
}

65
application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.entitiy;
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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
@ -31,75 +32,81 @@ 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 org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
public interface TbNotificationEntityService {
<E extends HasName, I extends EntityId> void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, SecurityUser user, Exception e,
Object... additionalInfo);
<I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, ActionType actionType, User user,
Exception e, Object... additionalInfo);
<E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, ActionType actionType,
User user, Object... additionalInfo);
<E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, ActionType actionType,
User user, Exception e, Object... additionalInfo);
<E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, User user, Object... additionalInfo);
<E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
ActionType actionType, User user, Exception e,
Object... additionalInfo);
<E extends HasName, I extends EntityId> void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType,
SecurityUser user, Object... additionalInfo);
User user, Object... additionalInfo);
<E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType,
List<EdgeId> relatedEdgeIds,
SecurityUser user, Object... additionalInfo);
User user, Object... additionalInfo);
void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId,
CustomerId customerId, List<EdgeId> relatedEdgeIds,
SecurityUser user, String body, Object... additionalInfo);
void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId,
List<EdgeId> relatedEdgeIds, User user, String body, Object... additionalInfo);
void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain,
List<EdgeId> relatedEdgeIds, SecurityUser user);
List<EdgeId> relatedEdgeIds, User user);
<I extends EntityId> void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType);
<E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
CustomerId customerId, E entity,
ActionType actionType,
EdgeEventActionType edgeActionType,
SecurityUser user, boolean sendToEdge,
User user, boolean sendToEdge,
Object... additionalInfo);
<E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
CustomerId customerId, EdgeId edgeId,
E entity, ActionType actionType,
SecurityUser user, Object... additionalInfo);
void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event);
User user, Object... additionalInfo);
void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event);
void notifyDeleteTenant(Tenant tenant);
void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
Device oldDevice, ActionType actionType, SecurityUser user, Object... additionalInfo);
Device oldDevice, ActionType actionType, User user, Object... additionalInfo);
void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
List<EdgeId> relatedEdgeIds, SecurityUser user, Object... additionalInfo);
List<EdgeId> relatedEdgeIds, User user, Object... additionalInfo);
void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
DeviceCredentials deviceCredentials, SecurityUser user);
DeviceCredentials deviceCredentials, User user);
void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId,
Device device, Tenant tenant, SecurityUser user, Object... additionalInfo);
Device device, Tenant tenant, User user, Object... additionalInfo);
void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType,
SecurityUser user, Object... additionalInfo);
User user, Object... additionalInfo);
void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo);
void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, User user, Object... additionalInfo);
<E extends HasName, I extends EntityId> void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId,
I entityId, E entity, SecurityUser user,
ActionType actionType, boolean sendNotifyMsgToEdge, Exception e,
Object... additionalInfo);
void notifyCreateOrUpdateOrDeleteRelation(TenantId tenantId, CustomerId customerId,
EntityRelation relation, SecurityUser user,
ActionType actionType, Exception e,
Object... additionalInfo);
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);
}

55
application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java

@ -15,29 +15,31 @@
*/
package org.thingsboard.server.service.entitiy.alarm;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
@Service
@TbCoreComponent
@AllArgsConstructor
public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService {
@Override
public Alarm save(Alarm alarm, SecurityUser user) throws ThingsboardException {
public Alarm save(Alarm alarm, User user) throws ThingsboardException {
ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = alarm.getTenantId();
try {
@ -45,46 +47,41 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
notificationEntityService.notifyCreateOrUpdateAlarm(savedAlarm, actionType, user);
return savedAlarm;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ALARM), alarm, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM), alarm, actionType, user, e);
throw e;
}
}
@Override
public void ack(Alarm alarm, SecurityUser user) throws ThingsboardException {
try {
long ackTs = System.currentTimeMillis();
alarmService.ackAlarm(user.getTenantId(), alarm.getId(), ackTs).get();
public ListenableFuture<Void> ack(Alarm alarm, User user) {
long ackTs = System.currentTimeMillis();
ListenableFuture<AlarmOperationResult> future = alarmService.ackAlarm(alarm.getTenantId(), alarm.getId(), ackTs);
return Futures.transform(future, result -> {
alarm.setAckTs(ackTs);
alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK);
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user);
} catch (Exception e) {
throw handleException(e);
}
return null;
}, MoreExecutors.directExecutor());
}
@Override
public void clear(Alarm alarm, SecurityUser user) throws ThingsboardException {
try {
long clearTs = System.currentTimeMillis();
alarmService.clearAlarm(user.getTenantId(), alarm.getId(), null, clearTs).get();
public ListenableFuture<Void> clear(Alarm alarm, User user) {
long clearTs = System.currentTimeMillis();
ListenableFuture<AlarmOperationResult> future = alarmService.clearAlarm(alarm.getTenantId(), alarm.getId(), null, clearTs);
return Futures.transform(future, result -> {
alarm.setClearTs(clearTs);
alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK);
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user);
} catch (Exception e) {
throw handleException(e);
}
return null;
}, MoreExecutors.directExecutor());
}
@Override
public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException {
try {
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator());
notificationEntityService.notifyDeleteAlarm(user.getTenantId(), alarm, alarm.getOriginator(), user.getCustomerId(),
relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm));
return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful();
} catch (Exception e) {
throw handleException(e);
}
public Boolean delete(Alarm alarm, User user) {
TenantId tenantId = alarm.getTenantId();
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, alarm.getOriginator());
notificationEntityService.notifyDeleteAlarm(tenantId, alarm, alarm.getOriginator(), alarm.getCustomerId(),
relatedEdgeIds, user, JacksonUtil.toString(alarm));
return alarmService.deleteAlarm(tenantId, alarm.getId()).isSuccessful();
}
}

11
application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java

@ -15,17 +15,18 @@
*/
package org.thingsboard.server.service.entitiy.alarm;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbAlarmService {
Alarm save(Alarm entity, SecurityUser user) throws ThingsboardException;
Alarm save(Alarm entity, User user) throws ThingsboardException;
void ack(Alarm alarm, SecurityUser user) throws ThingsboardException;
ListenableFuture<Void> ack(Alarm alarm, User user);
void clear(Alarm alarm, SecurityUser user) throws ThingsboardException;
ListenableFuture<Void> clear(Alarm alarm, User user);
Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException;
Boolean delete(Alarm alarm, User user);
}

80
application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java

@ -20,116 +20,111 @@ import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.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.queue.util.TbCoreComponent;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
@Service
@TbCoreComponent
@AllArgsConstructor
public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService {
private final AssetService assetService;
@Override
public Asset save(Asset asset, SecurityUser user) throws ThingsboardException {
public Asset save(Asset asset, User user) throws Exception {
ActionType actionType = asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = asset.getTenantId();
try {
Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), asset, savedAsset.getCustomerId(), actionType, user);
autoCommit(user, savedAsset.getId());
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), savedAsset,
asset.getCustomerId(), actionType, user);
return savedAsset;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), asset, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), asset, actionType, user, e);
throw e;
}
}
@Override
public ListenableFuture<Void> delete(Asset asset, SecurityUser user) throws ThingsboardException {
public ListenableFuture<Void> delete(Asset asset, User user) {
TenantId tenantId = asset.getTenantId();
AssetId assetId = asset.getId();
try {
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId);
assetService.deleteAsset(tenantId, assetId);
notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED,
relatedEdgeIds, user, assetId.toString());
notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(),
ActionType.DELETED, relatedEdgeIds, user, assetId.toString());
return removeAlarmsByEntityId(tenantId, assetId);
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
ActionType.DELETED, user, e, assetId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), ActionType.DELETED, user, e,
assetId.toString());
throw e;
}
}
@Override
public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException {
public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId();
try {
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName());
actionType, user, true, assetId.toString(), customerId.toString(), customer.getName());
return savedAsset;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
actionType, user, e, assetId.toString(), customerId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e,
assetId.toString(), customerId.toString());
throw e;
}
}
@Override
public Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException {
public Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
try {
Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId));
CustomerId customerId = customer.getId();
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user,
true, customerId.toString(), customer.getName());
actionType, user, true, assetId.toString(), customerId.toString(), customer.getName());
return savedAsset;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
actionType, user, e, assetId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e, assetId.toString());
throw e;
}
}
@Override
public Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, SecurityUser user) throws ThingsboardException {
public Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset,
actionType, null, user, false, actionType.toString(),
publicCustomer.getId().toString(), publicCustomer.getName());
actionType, user, false, actionType.toString(), publicCustomer.getId().toString(), publicCustomer.getName());
return savedAsset;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
actionType, user, e, assetId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e, assetId.toString());
throw e;
}
}
@Override
public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, SecurityUser user) throws ThingsboardException {
public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
EdgeId edgeId = edge.getId();
try {
@ -139,14 +134,14 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
return savedAsset;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
actionType, user, e, assetId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType,
user, e, assetId.toString(), edgeId.toString());
throw e;
}
}
@Override
public Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, SecurityUser user) throws ThingsboardException {
public Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
AssetId assetId = asset.getId();
EdgeId edgeId = edge.getId();
@ -155,11 +150,12 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(),
edgeId, asset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName());
return savedAsset;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
actionType, user, e, assetId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType,
user, e, assetId.toString(), edgeId.toString());
throw e;
}
}
}

16
application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java

@ -17,27 +17,27 @@ package org.thingsboard.server.service.entitiy.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbAssetService {
Asset save(Asset asset, SecurityUser user) throws ThingsboardException;
Asset save(Asset asset, User user) throws Exception;
ListenableFuture<Void> delete(Asset asset, SecurityUser user) throws ThingsboardException;
ListenableFuture<Void> delete(Asset asset, User user);
Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException;
Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, User user) throws ThingsboardException;
Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException;
Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, User user) throws ThingsboardException;
Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, SecurityUser user) throws ThingsboardException;
Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, User user) throws ThingsboardException;
Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, SecurityUser user) throws ThingsboardException;
Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, User user) throws ThingsboardException;
Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, SecurityUser user) throws ThingsboardException;
Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, User user) throws ThingsboardException;
}

24
application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java

@ -19,41 +19,37 @@ import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
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.exception.ThingsboardException;
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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
@Service
@TbCoreComponent
@AllArgsConstructor
public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService {
@Override
public Customer save(Customer customer, SecurityUser user) throws ThingsboardException {
public Customer save(Customer customer, User user) throws Exception {
ActionType actionType = customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = customer.getTenantId();
CustomerId customerId = customer.getId();
try {
Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer));
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, customerId, actionType, user);
autoCommit(user, savedCustomer.getId());
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, null, actionType, user);
return savedCustomer;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), customer, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), customer, actionType, user, e);
throw e;
}
}
@Override
public void delete(Customer customer, SecurityUser user) throws ThingsboardException {
public void delete(Customer customer, User user) {
TenantId tenantId = customer.getTenantId();
CustomerId customerId = customer.getId();
try {
@ -63,9 +59,9 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements
ActionType.DELETED, relatedEdgeIds, user, customerId.toString());
tbClusterService.broadcastEntityStateChangeEvent(tenantId, customer.getId(), ComponentLifecycleEvent.DELETED);
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null,
ActionType.DELETED, user, e, customer.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), ActionType.DELETED,
user, e, customerId.toString());
throw e;
}
}
}

176
application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java

@ -21,17 +21,17 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.HashSet;
import java.util.List;
@ -42,23 +42,26 @@ import java.util.Set;
@AllArgsConstructor
public class DefaultTbDashboardService extends AbstractTbEntityService implements TbDashboardService {
private final DashboardService dashboardService;
@Override
public Dashboard save(Dashboard dashboard, SecurityUser user) throws ThingsboardException {
public Dashboard save(Dashboard dashboard, User user) throws Exception {
ActionType actionType = dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = dashboard.getTenantId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard));
autoCommit(user, savedDashboard.getId());
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedDashboard.getId(), savedDashboard,
null, actionType, user);
return savedDashboard;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), dashboard, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), dashboard, actionType, user, e);
throw e;
}
}
@Override
public void delete(Dashboard dashboard, SecurityUser user) throws ThingsboardException {
public void delete(Dashboard dashboard, User user) {
DashboardId dashboardId = dashboard.getId();
TenantId tenantId = dashboard.getTenantId();
try {
@ -67,66 +70,70 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null,
ActionType.DELETED, relatedEdgeIds, user, dashboardId.toString());
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null,
ActionType.DELETED, user, e, dashboardId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), ActionType.DELETED, user, e, dashboardId.toString());
throw e;
}
}
@Override
public Dashboard assignDashboardToCustomer(DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException {
public Dashboard assignDashboardToCustomer(Dashboard dashboard, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
CustomerId customerId = customer.getId();
DashboardId dashboardId = dashboard.getId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(user.getTenantId(), dashboardId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboardId, customerId, savedDashboard,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName());
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
actionType, user, true, dashboardId.toString(), customerId.toString(), customer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboardId.toString(), customerId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType,
user, e, dashboardId.toString(), customerId.toString());
throw e;
}
}
@Override
public Dashboard assignDashboardToPublicCustomer(DashboardId dashboardId, SecurityUser user) throws ThingsboardException {
public Dashboard assignDashboardToPublicCustomer(Dashboard dashboard, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(user.getTenantId());
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(user.getTenantId(), dashboardId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboardId, user.getCustomerId(), savedDashboard,
actionType, null, user, false, dashboardId.toString(),
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), savedDashboard,
actionType, user, false, dashboardId.toString(),
publicCustomer.getId().toString(), publicCustomer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboardId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}
@Override
public Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, SecurityUser user) throws ThingsboardException {
public Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId());
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(user.getTenantId(), dashboard.getId(), publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboard.getId(), user.getCustomerId(), dashboard,
actionType, null, user, false, dashboard.getId().toString(),
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), dashboard,
actionType, user, false, dashboardId.toString(),
publicCustomer.getId().toString(), publicCustomer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboard.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}
@Override
public Dashboard updateDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, SecurityUser user) throws ThingsboardException {
public Dashboard updateDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = user.getTenantId();
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
Set<CustomerId> addedCustomerIds = new HashSet<>();
Set<CustomerId> removedCustomerIds = new HashSet<>();
@ -150,94 +157,105 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
} else {
Dashboard savedDashboard = null;
for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId));
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerInfo.getTitle());
actionType, user, true, 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, dashboard.getId(), customerId));
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard,
ActionType.UNASSIGNED_FROM_CUSTOMER, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customerInfo.getTitle());
ActionType.UNASSIGNED_FROM_CUSTOMER, user, true, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
return savedDashboard;
}
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboard.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}
@Override
public Dashboard addDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, SecurityUser user) throws ThingsboardException {
public Dashboard addDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = user.getTenantId();
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
if (customerIds.isEmpty()) {
Set<CustomerId> addedCustomerIds = new HashSet<>();
for (CustomerId customerId : customerIds) {
if (!dashboard.isAssignedToCustomer(customerId)) {
addedCustomerIds.add(customerId);
}
}
if (addedCustomerIds.isEmpty()) {
return dashboard;
} else {
Dashboard savedDashboard = null;
for (CustomerId customerId : customerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId));
for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerInfo.getTitle());
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
actionType, user, true, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
return savedDashboard;
}
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboard.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}
@Override
public Dashboard removeDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, SecurityUser user) throws ThingsboardException {
public Dashboard removeDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = user.getTenantId();
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
if (customerIds.isEmpty()) {
Set<CustomerId> removedCustomerIds = new HashSet<>();
for (CustomerId customerId : customerIds) {
if (dashboard.isAssignedToCustomer(customerId)) {
removedCustomerIds.add(customerId);
}
}
if (removedCustomerIds.isEmpty()) {
return dashboard;
} else {
Dashboard savedDashboard = null;
for (CustomerId customerId : customerIds) {
for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customerInfo.getTitle());
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
actionType, user, true, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
}
return savedDashboard;
}
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboard.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}
@Override
public Dashboard asignDashboardToEdge(DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException {
public Dashboard asignDashboardToEdge(TenantId tenantId, DashboardId dashboardId, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
TenantId tenantId = user.getTenantId();
EdgeId edgeId = edge.getId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(tenantId, dashboardId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, user.getCustomerId(),
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, null,
edgeId, savedDashboard, actionType, user, dashboardId.toString(),
edgeId.toString(), edge.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, dashboardId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
actionType, user, e, dashboardId.toString(), edgeId);
throw e;
}
}
@Override
public Dashboard unassignDashboardFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException {
public Dashboard unassignDashboardFromEdge(Dashboard dashboard, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
@ -245,30 +263,30 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
try {
Dashboard savedDevice = checkNotNull(dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, user.getCustomerId(),
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, null,
edgeId, dashboard, actionType, user, dashboardId.toString(),
edgeId.toString(), edge.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboardId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e,
dashboardId.toString(), edgeId.toString());
throw e;
}
}
@Override
public Dashboard unassignDashboardFromCustomer(Dashboard dashboard, Customer customer, SecurityUser user) throws ThingsboardException {
public Dashboard unassignDashboardFromCustomer(Dashboard dashboard, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), customer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboard.getId(), customer.getId(), savedDashboard,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customer.getId().toString(), customer.getName());
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customer.getId(), savedDashboard,
actionType, user, true, dashboardId.toString(), customer.getId().toString(), customer.getName());
return savedDashboard;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null,
actionType, user, e, dashboard.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
throw e;
}
}

23
application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java

@ -17,33 +17,34 @@ package org.thingsboard.server.service.entitiy.dashboard;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException;
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.service.entitiy.SimpleTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Set;
public interface TbDashboardService extends SimpleTbEntityService<Dashboard> {
public interface TbDashboardService extends SimpleTbEntityService<Dashboard> {
Dashboard assignDashboardToCustomer(DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException;
Dashboard assignDashboardToCustomer(Dashboard dashboard, Customer customer, User user) throws ThingsboardException;
Dashboard assignDashboardToPublicCustomer(DashboardId dashboardId, SecurityUser user) throws ThingsboardException;
Dashboard assignDashboardToPublicCustomer(Dashboard dashboard, User user) throws ThingsboardException;
Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, SecurityUser user) throws ThingsboardException;
Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, User user) throws ThingsboardException;
Dashboard updateDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, SecurityUser user) throws ThingsboardException;
Dashboard updateDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, User user) throws ThingsboardException;
Dashboard addDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, SecurityUser user) throws ThingsboardException;
Dashboard addDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, User user) throws ThingsboardException;
Dashboard removeDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, SecurityUser user) throws ThingsboardException;
Dashboard removeDashboardCustomers(Dashboard dashboard, Set<CustomerId> customerIds, User user) throws ThingsboardException;
Dashboard asignDashboardToEdge(DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException;
Dashboard asignDashboardToEdge(TenantId tenantId, DashboardId dashboardId, Edge edge, User user) throws ThingsboardException;
Dashboard unassignDashboardFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException;
Dashboard unassignDashboardFromEdge(Dashboard dashboard, Edge edge, User user) throws ThingsboardException;
Dashboard unassignDashboardFromCustomer(Dashboard dashboard, Customer customer, SecurityUser user) throws ThingsboardException;
Dashboard unassignDashboardFromCustomer(Dashboard dashboard, Customer customer, User user) throws ThingsboardException;
}

169
application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java

@ -25,21 +25,24 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
@ -49,24 +52,32 @@ import java.util.List;
@Slf4j
public class DefaultTbDeviceService extends AbstractTbEntityService implements TbDeviceService {
private final DeviceService deviceService;
private final DeviceCredentialsService deviceCredentialsService;
private final ClaimDevicesService claimDevicesService;
private final TenantService tenantService;
@Override
public Device save(TenantId tenantId, Device device, Device oldDevice, String accessToken, SecurityUser user) throws ThingsboardException {
public Device save(Device device, Device oldDevice, String accessToken, User user) throws Exception {
ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = device.getTenantId();
try {
Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
autoCommit(user, savedDevice.getId());
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
savedDevice, oldDevice, actionType, user);
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), device, actionType, user, e);
throw e;
}
}
@Override
public Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials credentials, SecurityUser user) throws ThingsboardException {
public Device saveDeviceWithCredentials(Device device, DeviceCredentials credentials, User user) throws ThingsboardException {
ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = device.getTenantId();
try {
Device savedDevice = checkNotNull(deviceService.saveDeviceWithCredentials(device, credentials));
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
@ -74,13 +85,14 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), device,
actionType, user, e);
throw e;
}
}
@Override
public ListenableFuture<Void> delete(Device device, SecurityUser user) throws ThingsboardException {
public ListenableFuture<Void> delete(Device device, User user) {
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
try {
@ -91,31 +103,31 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
return removeAlarmsByEntityId(tenantId, deviceId);
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
ActionType.DELETED, user, e, deviceId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), ActionType.DELETED,
user, e, deviceId.toString());
throw e;
}
}
@Override
public Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException {
public Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId();
try {
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(user.getTenantId(), deviceId, customerId));
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName());
actionType, user, true, deviceId.toString(), customerId.toString(), customer.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, deviceId.toString(), customerId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), actionType, user,
e, deviceId.toString(), customerId.toString());
throw e;
}
}
@Override
public Device unassignDeviceFromCustomer(Device device, Customer customer, SecurityUser user) throws ThingsboardException {
public Device unassignDeviceFromCustomer(Device device, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
@ -124,55 +136,53 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
CustomerId customerId = customer.getId();
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user,
true, customerId.toString(), customer.getName());
actionType, user, true, deviceId.toString(), customerId.toString(), customer.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, deviceId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), actionType,
user, e, deviceId.toString());
throw e;
}
}
@Override
public Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, SecurityUser user) throws ThingsboardException {
public Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice,
actionType, null, user, false, deviceId.toString(),
actionType, user, false, deviceId.toString(),
publicCustomer.getId().toString(), publicCustomer.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, deviceId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), actionType,
user, e, deviceId.toString());
throw e;
}
}
@Override
public DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.CREDENTIALS_READ;
public DeviceCredentials getDeviceCredentialsByDeviceId(Device device, User user) throws ThingsboardException {
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
try {
DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId));
notificationEntityService.notifyEntity(tenantId, deviceId, device, device.getCustomerId(),
actionType, user, null, deviceId.toString());
notificationEntityService.logEntityAction(tenantId, deviceId, device, device.getCustomerId(),
ActionType.CREDENTIALS_READ, user, deviceId.toString());
return deviceCredentials;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, deviceId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.CREDENTIALS_READ, user, e, deviceId.toString());
throw e;
}
}
@Override
public DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException {
public DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, User user) throws ThingsboardException {
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
try {
@ -180,69 +190,63 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
notificationEntityService.notifyUpdateDeviceCredentials(tenantId, deviceId, device.getCustomerId(), device, result, user);
return result;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.CREDENTIALS_UPDATED, user, e, deviceCredentials);
throw handleException(e);
throw e;
}
}
@Override
public ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException {
try {
ListenableFuture<ClaimResult> future = claimDevicesService.claimDevice(device, customerId, secretKey);
public ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, User user) {
ListenableFuture<ClaimResult> future = claimDevicesService.claimDevice(device, customerId, secretKey);
return Futures.transform(future, result -> {
if (result != null && result.getResponse().equals(ClaimResponse.SUCCESS)) {
notificationEntityService.notifyEntity(tenantId, device.getId(), result.getDevice(), customerId,
ActionType.ASSIGNED_TO_CUSTOMER, user, null, device.getId().toString(), customerId.toString(),
customerService.findCustomerById(tenantId, customerId).getName());
}
return result;
}, MoreExecutors.directExecutor());
} catch (Exception e) {
throw handleException(e);
}
return Futures.transform(future, result -> {
if (result != null && result.getResponse().equals(ClaimResponse.SUCCESS)) {
notificationEntityService.logEntityAction(tenantId, device.getId(), result.getDevice(), customerId,
ActionType.ASSIGNED_TO_CUSTOMER, user, device.getId().toString(), customerId.toString(),
customerService.findCustomerById(tenantId, customerId).getName());
}
return result;
}, MoreExecutors.directExecutor());
}
@Override
public ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException {
try {
ListenableFuture<ReclaimResult> future = claimDevicesService.reClaimDevice(tenantId, device);
public ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, User user) {
ListenableFuture<ReclaimResult> future = claimDevicesService.reClaimDevice(tenantId, device);
return Futures.transform(future, result -> {
Customer unassignedCustomer = result.getUnassignedCustomer();
if (unassignedCustomer != null) {
notificationEntityService.notifyEntity(tenantId, device.getId(), device, device.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, user, null,
device.getId().toString(), unassignedCustomer.getId().toString(), unassignedCustomer.getName());
}
return result;
}, MoreExecutors.directExecutor());
} catch (Exception e) {
throw handleException(e);
}
return Futures.transform(future, result -> {
Customer unassignedCustomer = result.getUnassignedCustomer();
if (unassignedCustomer != null) {
notificationEntityService.logEntityAction(tenantId, device.getId(), device, device.getCustomerId(),
ActionType.UNASSIGNED_FROM_CUSTOMER, user, device.getId().toString(),
unassignedCustomer.getId().toString(), unassignedCustomer.getName());
}
return result;
}, MoreExecutors.directExecutor());
}
@Override
public Device assignDeviceToTenant(Device device, Tenant newTenant, SecurityUser user) throws ThingsboardException {
public Device assignDeviceToTenant(Device device, Tenant newTenant, User user) {
TenantId tenantId = device.getTenantId();
TenantId newTenantId = newTenant.getId();
DeviceId deviceId = device.getId();
try {
Tenant tenant = tenantService.findTenantById(tenantId);
Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device);
notificationEntityService.notifyAssignDeviceToTenant(tenantId, newTenantId, device.getId(),
notificationEntityService.notifyAssignDeviceToTenant(tenantId, newTenantId, deviceId,
assignedDevice.getCustomerId(), assignedDevice, tenant, user, newTenantId.toString(), newTenant.getName());
return assignedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
ActionType.ASSIGNED_TO_TENANT, user, e, newTenantId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.ASSIGNED_TO_TENANT, user, e, deviceId.toString());
throw e;
}
}
@Override
public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, SecurityUser user) throws ThingsboardException {
public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
EdgeId edgeId = edge.getId();
try {
@ -251,15 +255,14 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
edgeId, savedDevice, actionType, user, deviceId.toString(), edgeId.toString(), edge.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, deviceId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.ASSIGNED_TO_EDGE, user, e, deviceId.toString(), edgeId.toString());
throw e;
}
}
@Override
public Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
public Device unassignDeviceFromEdge(Device device, Edge edge, User user) throws ThingsboardException {
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
EdgeId edgeId = edge.getId();
@ -267,12 +270,12 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, device.getCustomerId(),
edgeId, device, actionType, user, deviceId.toString(), edgeId.toString(), edge.getName());
edgeId, device, ActionType.UNASSIGNED_FROM_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName());
return savedDevice;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, deviceId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.UNASSIGNED_FROM_EDGE, user, e, deviceId.toString(), edgeId.toString());
throw e;
}
}

28
application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java

@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
@ -27,33 +28,32 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbDeviceService {
Device save(TenantId tenantId, Device device, Device oldDevice, String accessToken, SecurityUser user) throws ThingsboardException;
Device save(Device device, Device oldDevice, String accessToken, User user) throws Exception;
Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException;
Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials, User user) throws ThingsboardException;
ListenableFuture<Void> delete(Device device, SecurityUser user) throws ThingsboardException;
ListenableFuture<Void> delete(Device device, User user);
Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException;
Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, User user) throws ThingsboardException;
Device unassignDeviceFromCustomer(Device device, Customer customer, SecurityUser user) throws ThingsboardException;
Device unassignDeviceFromCustomer(Device device, Customer customer, User user) throws ThingsboardException;
Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, SecurityUser user) throws ThingsboardException;
Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, User user) throws ThingsboardException;
DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException;
DeviceCredentials getDeviceCredentialsByDeviceId(Device device, User user) throws ThingsboardException;
DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException;
DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, User user) throws ThingsboardException;
ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException;
ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, User user);
ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException;
ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, User user);
Device assignDeviceToTenant(Device device, Tenant newTenant, SecurityUser user) throws ThingsboardException;
Device assignDeviceToTenant(Device device, Tenant newTenant, User user);
Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, SecurityUser user) throws ThingsboardException;
Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, User user) throws ThingsboardException;
Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException;
Device unassignDeviceFromEdge(Device device, Edge edge, User user) throws ThingsboardException;
}

52
application/src/main/java/org/thingsboard/server/service/entitiy/deviceProfile/DefaultTbDeviceProfileService.java → application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java

@ -13,21 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.deviceProfile;
package org.thingsboard.server.service.entitiy.device.profile;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile;
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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import java.util.Objects;
@ -36,8 +38,12 @@ import java.util.Objects;
@AllArgsConstructor
@Slf4j
public class DefaultTbDeviceProfileService extends AbstractTbEntityService implements TbDeviceProfileService {
private final DeviceProfileService deviceProfileService;
private final OtaPackageStateService otaPackageStateService;
@Override
public DeviceProfile save(DeviceProfile deviceProfile, SecurityUser user) throws ThingsboardException {
public DeviceProfile save(DeviceProfile deviceProfile, User user) throws Exception {
ActionType actionType = deviceProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = deviceProfile.getTenantId();
try {
@ -54,23 +60,24 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple
}
}
DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
autoCommit(user, savedDeviceProfile.getId());
tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedDeviceProfile.getId(),
actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedDeviceProfile.getId(), savedDeviceProfile, user, actionType, true, null);
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedDeviceProfile.getId(),
savedDeviceProfile, user, actionType, true, null);
return savedDeviceProfile;
} catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.DEVICE_PROFILE), deviceProfile, user, actionType, false, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), deviceProfile, actionType, user, e);
throw e;
}
}
@Override
public void delete(DeviceProfile deviceProfile, SecurityUser user) throws ThingsboardException {
public void delete(DeviceProfile deviceProfile, User user) {
DeviceProfileId deviceProfileId = deviceProfile.getId();
TenantId tenantId = deviceProfile.getTenantId();
try {
@ -78,34 +85,35 @@ 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.notifyCreateOrUpdateOrDelete(tenantId, null, deviceProfileId, deviceProfile,
user, ActionType.DELETED, true, null, deviceProfileId.toString());
} catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.DEVICE_PROFILE), null, user, ActionType.DELETED, false, e, deviceProfileId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), ActionType.DELETED,
user, e, deviceProfileId.toString());
throw e;
}
}
@Override
public DeviceProfile setDefaultDeviceProfile(DeviceProfile deviceProfile, DeviceProfile previousDefaultDeviceProfile, SecurityUser user) throws ThingsboardException {
public DeviceProfile setDefaultDeviceProfile(DeviceProfile deviceProfile, DeviceProfile previousDefaultDeviceProfile, User user) throws ThingsboardException {
TenantId tenantId = deviceProfile.getTenantId();
DeviceProfileId deviceProfileId = deviceProfile.getId();
try {
if (deviceProfileService.setDefaultDeviceProfile(tenantId, deviceProfile.getId())) {
if (deviceProfileService.setDefaultDeviceProfile(tenantId, deviceProfileId)) {
if (previousDefaultDeviceProfile != null) {
previousDefaultDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, previousDefaultDeviceProfile.getId());
notificationEntityService.notifyEntity(tenantId, previousDefaultDeviceProfile.getId(), previousDefaultDeviceProfile, null,
ActionType.UPDATED, user, null);
notificationEntityService.logEntityAction(tenantId, previousDefaultDeviceProfile.getId(), previousDefaultDeviceProfile,
ActionType.UPDATED, user);
}
deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfile.getId());
deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
notificationEntityService.notifyEntity(tenantId, deviceProfile.getId(), deviceProfile, null,
ActionType.UPDATED, user, null);
notificationEntityService.logEntityAction(tenantId, deviceProfileId, deviceProfile, ActionType.UPDATED, user);
}
return deviceProfile;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE_PROFILE), null, null,
ActionType.UPDATED, user, e, deviceProfile.getId().toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), ActionType.UPDATED,
user, e, deviceProfileId.toString());
throw e;
}
}
}

6
application/src/main/java/org/thingsboard/server/service/entitiy/deviceProfile/TbDeviceProfileService.java → application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/TbDeviceProfileService.java

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.deviceProfile;
package org.thingsboard.server.service.entitiy.device.profile;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.entitiy.SimpleTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbDeviceProfileService extends SimpleTbEntityService<DeviceProfile> {
DeviceProfile setDefaultDeviceProfile(DeviceProfile deviceProfile, DeviceProfile previousDefaultDeviceProfile, SecurityUser user) throws ThingsboardException;
DeviceProfile setDefaultDeviceProfile(DeviceProfile deviceProfile, DeviceProfile previousDefaultDeviceProfile, User user) throws ThingsboardException;
}

71
application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java

@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException;
@ -28,9 +29,10 @@ 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.rule.RuleChain;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
@AllArgsConstructor
@TbCoreComponent
@ -38,8 +40,11 @@ import org.thingsboard.server.service.security.model.SecurityUser;
@Slf4j
public class DefaultTbEdgeService extends AbstractTbEntityService implements TbEdgeService {
private final EdgeNotificationService edgeNotificationService;
private final RuleChainService ruleChainService;
@Override
public Edge save(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException {
public Edge save(Edge edge, RuleChain edgeTemplateRootRuleChain, User user) throws Exception {
ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = edge.getTenantId();
try {
@ -56,95 +61,89 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE
return savedEdge;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE), edge, actionType, user, e);
throw e;
}
}
@Override
public void delete(Edge edge, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.DELETED;
public void delete(Edge edge, User user) {
EdgeId edgeId = edge.getId();
TenantId tenantId = edge.getTenantId();
try {
edgeService.deleteEdge(tenantId, edgeId);
notificationEntityService.notifyEdge(tenantId, edgeId, edge.getCustomerId(), edge, actionType, user, edgeId.toString());
notificationEntityService.notifyEdge(tenantId, edgeId, edge.getCustomerId(), edge, ActionType.DELETED, user, edgeId.toString());
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType,
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE), ActionType.DELETED,
user, e, edgeId.toString());
throw handleException(e);
throw e;
}
}
@Override
public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, User user) throws ThingsboardException {
CustomerId customerId = customer.getId();
try {
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId));
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, ActionType.ASSIGNED_TO_CUSTOMER, user,
edgeId.toString(), customerId.toString(), customer.getName());
return savedEdge;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
actionType, user, e, edgeId.toString(), customerId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
ActionType.ASSIGNED_TO_CUSTOMER, user, e, edgeId.toString(), customerId.toString());
throw e;
}
}
@Override
public Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
public Edge unassignEdgeFromCustomer(Edge edge, Customer customer, User user) throws ThingsboardException {
TenantId tenantId = edge.getTenantId();
EdgeId edgeId = edge.getId();
CustomerId customerId = customer.getId();
try {
Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(tenantId, edgeId));
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, ActionType.UNASSIGNED_FROM_CUSTOMER, user,
edgeId.toString(), customerId.toString(), customer.getName());
return savedEdge;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
actionType, user, e, edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
ActionType.UNASSIGNED_FROM_CUSTOMER, user, e, edgeId.toString());
throw e;
}
}
@Override
public Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
public Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, User user) throws ThingsboardException {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
CustomerId customerId = publicCustomer.getId();
try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
CustomerId customerId = publicCustomer.getId();
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId));
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, ActionType.ASSIGNED_TO_CUSTOMER, user,
edgeId.toString(), customerId.toString(), publicCustomer.getName());
return savedEdge;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
actionType, user, e, edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
ActionType.ASSIGNED_TO_CUSTOMER, user, e, edgeId.toString());
throw e;
}
}
@Override
public Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.UPDATED;
public Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, User user) throws Exception {
TenantId tenantId = edge.getTenantId();
EdgeId edgeId = edge.getId();
try {
Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, ruleChainId);
notificationEntityService.notifyEdge(tenantId, edgeId, null, updatedEdge, actionType, user);
notificationEntityService.notifyEdge(tenantId, edgeId, null, updatedEdge, ActionType.UPDATED, user);
return updatedEdge;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
actionType, user, e, edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
ActionType.UPDATED, user, e, edgeId.toString());
throw e;
}
}
}

14
application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java

@ -16,24 +16,24 @@
package org.thingsboard.server.service.entitiy.edge;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException;
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.rule.RuleChain;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbEdgeService {
Edge save(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException;
Edge save(Edge edge, RuleChain edgeTemplateRootRuleChain, User user) throws Exception;
void delete(Edge edge, SecurityUser user) throws ThingsboardException;
void delete(Edge edge, User user);
Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException;
Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, User user) throws ThingsboardException;
Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException;
Edge unassignEdgeFromCustomer(Edge edge, Customer customer, User user) throws ThingsboardException;
Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException;
Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, User user) throws ThingsboardException;
Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException;
Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, User user) throws Exception;
}

49
application/src/main/java/org/thingsboard/server/service/entitiy/entityRelation/DefaultTbEntityRelationService.java → application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java

@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.entityRelation;
package org.thingsboard.server.service.entitiy.entity.relation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
@ -25,52 +26,60 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
@Service
@TbCoreComponent
@AllArgsConstructor
@Slf4j
public class DefaultTbEntityRelationService extends AbstractTbEntityService implements TbEntityRelationService {
private final RelationService relationService;
@Override
public void save(TenantId tenantId, CustomerId customerId, EntityRelation relation, SecurityUser user) throws ThingsboardException {
public void save(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException {
try {
relationService.saveRelation(tenantId, relation);
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId,
relation, user, ActionType.RELATION_ADD_OR_UPDATE, null, relation);
notificationEntityService.notifyRelation(tenantId, customerId,
relation, user, ActionType.RELATION_ADD_OR_UPDATE, relation);
} catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId,
relation, user, ActionType.RELATION_ADD_OR_UPDATE, e, relation);
throw handleException(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);
throw e;
}
}
@Override
public void delete(TenantId tenantId, CustomerId customerId, EntityRelation relation, SecurityUser user) throws ThingsboardException {
public void delete(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException {
try {
Boolean found = relationService.deleteRelation(tenantId, relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
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.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId,
relation, user, ActionType.RELATION_DELETED, null, relation);
notificationEntityService.notifyRelation(tenantId, customerId,
relation, user, ActionType.RELATION_DELETED, relation);
} catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId,
relation, user, ActionType.RELATION_DELETED, e, relation);
throw handleException(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);
throw e;
}
}
@Override
public void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, SecurityUser user) throws ThingsboardException {
public void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException {
try {
relationService.deleteEntityRelations(tenantId, entityId);
notificationEntityService.notifyEntity(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user, null);
notificationEntityService.logEntityAction(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user);
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, entityId, null, customerId,
ActionType.RELATIONS_DELETED, user, e);
throw e;
}
}
}
}

10
application/src/main/java/org/thingsboard/server/service/entitiy/entityRelation/TbEntityRelationService.java → application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java

@ -13,21 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.entityRelation;
package org.thingsboard.server.service.entitiy.entity.relation;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbEntityRelationService {
void save(TenantId tenantId, CustomerId customerId, EntityRelation entity, SecurityUser user) throws ThingsboardException;
void save(TenantId tenantId, CustomerId customerId, EntityRelation entity, User user) throws ThingsboardException;
void delete (TenantId tenantId, CustomerId customerId, EntityRelation entity, SecurityUser user) throws ThingsboardException;
void delete(TenantId tenantId, CustomerId customerId, EntityRelation entity, User user) throws ThingsboardException;
void deleteRelations (TenantId tenantId, CustomerId customerId, EntityId entityId, SecurityUser user) throws ThingsboardException;
void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException;
}

232
application/src/main/java/org/thingsboard/server/service/entitiy/entityView/DefaultTbEntityViewService.java → application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.entityView;
package org.thingsboard.server.service.entitiy.entityview;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
@ -23,13 +23,14 @@ import com.google.common.util.concurrent.SettableFuture;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
@ -40,73 +41,91 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
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.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank;
@Service
@TbCoreComponent
@AllArgsConstructor
@Slf4j
public class DefaultTbEntityViewService extends AbstractTbEntityService implements TbEntityViewService {
private final EntityViewService entityViewService;
private final AttributesService attributesService;
private final TelemetrySubscriptionService tsSubService;
private final TimeseriesService tsService;
final Map<TenantId, Map<EntityId, List<EntityView>>> localCache = new ConcurrentHashMap<>();
@Override
public EntityView save(EntityView entityView, EntityView existingEntityView, SecurityUser user) throws ThingsboardException {
public EntityView save(EntityView entityView, EntityView existingEntityView, User user) throws Exception {
ActionType actionType = entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = entityView.getTenantId();
try {
List<ListenableFuture<?>> futures = new ArrayList<>();
if (existingEntityView != null) {
if (existingEntityView.getKeys() != null && existingEntityView.getKeys().getAttributes() != null) {
futures.add(deleteAttributesFromEntityView(existingEntityView, DataConstants.CLIENT_SCOPE, existingEntityView.getKeys().getAttributes().getCs(), user));
futures.add(deleteAttributesFromEntityView(existingEntityView, DataConstants.SERVER_SCOPE, existingEntityView.getKeys().getAttributes().getCs(), user));
futures.add(deleteAttributesFromEntityView(existingEntityView, DataConstants.SHARED_SCOPE, existingEntityView.getKeys().getAttributes().getCs(), user));
}
List<String> tsKeys = existingEntityView.getKeys() != null && existingEntityView.getKeys().getTimeseries() != null ?
existingEntityView.getKeys().getTimeseries() : Collections.emptyList();
futures.add(deleteLatestFromEntityView(existingEntityView, tsKeys, user));
}
EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
if (savedEntityView.getKeys() != null) {
if (savedEntityView.getKeys().getAttributes() != null) {
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), user));
}
futures.add(copyLatestFromEntityToEntityView(savedEntityView, user));
}
for (ListenableFuture<?> future : futures) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Failed to copy attributes to entity view", e);
}
}
this.updateEntityViewAttributes(tenantId, savedEntityView, existingEntityView, user);
autoCommit(user, savedEntityView.getId());
notificationEntityService.notifyCreateOrUpdateEntity(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView,
null, actionType, user);
localCache.computeIfAbsent(savedEntityView.getTenantId(), (k) -> new ConcurrentReferenceHashMap<>()).clear();
tbClusterService.broadcastEntityStateChangeEvent(savedEntityView.getTenantId(), savedEntityView.getId(),
entityView.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
return savedEntityView;
} catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.ENTITY_VIEW), entityView, null, actionType, user, e);
throw handleException(e);
notificationEntityService.logEntityAction(user.getTenantId(), emptyId(EntityType.ENTITY_VIEW), entityView, actionType, user, e);
throw e;
}
}
@Override
public void updateEntityViewAttributes(TenantId tenantId, EntityView savedEntityView, EntityView oldEntityView, User user) throws ThingsboardException {
List<ListenableFuture<?>> futures = new ArrayList<>();
if (oldEntityView != null) {
if (oldEntityView.getKeys() != null && oldEntityView.getKeys().getAttributes() != null) {
futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.CLIENT_SCOPE, oldEntityView.getKeys().getAttributes().getCs(), user));
futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.SERVER_SCOPE, oldEntityView.getKeys().getAttributes().getSs(), user));
futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.SHARED_SCOPE, oldEntityView.getKeys().getAttributes().getSh(), user));
}
List<String> tsKeys = oldEntityView.getKeys() != null && oldEntityView.getKeys().getTimeseries() != null ?
oldEntityView.getKeys().getTimeseries() : Collections.emptyList();
futures.add(deleteLatestFromEntityView(oldEntityView, tsKeys, user));
}
if (savedEntityView.getKeys() != null) {
if (savedEntityView.getKeys().getAttributes() != null) {
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), user));
}
futures.add(copyLatestFromEntityToEntityView(tenantId, savedEntityView));
}
for (ListenableFuture<?> future : futures) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Failed to copy attributes to entity view", e);
}
}
}
@Override
public void delete(EntityView entityView, SecurityUser user) throws ThingsboardException {
public void delete(EntityView entityView, User user) throws ThingsboardException {
TenantId tenantId = entityView.getTenantId();
EntityViewId entityViewId = entityView.getId();
try {
@ -114,99 +133,142 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
entityViewService.deleteEntityView(tenantId, entityViewId);
notificationEntityService.notifyDeleteEntity(tenantId, entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED,
relatedEdgeIds, user, entityViewId.toString());
localCache.computeIfAbsent(tenantId, (k) -> new ConcurrentReferenceHashMap<>()).clear();
tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityViewId, ComponentLifecycleEvent.DELETED);
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null,
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
ActionType.DELETED, user, e, entityViewId.toString());
throw handleException(e);
throw e;
}
}
@Override
public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
CustomerId customerId = customer.getId();
try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, entityViewId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customerId, savedEntityView,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName());
ActionType.ASSIGNED_TO_CUSTOMER, user, true, entityViewId.toString(), customerId.toString(), customer.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null,
actionType, user, e, entityViewId.toString(), customerId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
ActionType.ASSIGNED_TO_CUSTOMER, user, e, entityViewId.toString(), customerId.toString());
throw e;
}
}
@Override
public EntityView assignEntityViewToPublicCustomer(TenantId tenantId, CustomerId customerId, Customer publicCustomer,
EntityViewId entityViewId, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
EntityViewId entityViewId, User user) throws ThingsboardException {
try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId,
entityViewId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customerId, savedEntityView,
actionType, null, user, false, savedEntityView.getEntityId().toString(),
ActionType.ASSIGNED_TO_CUSTOMER, user, false, savedEntityView.getEntityId().toString(),
publicCustomer.getId().toString(), publicCustomer.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null,
actionType, user, e, entityViewId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
ActionType.ASSIGNED_TO_CUSTOMER, user, e, entityViewId.toString());
throw e;
}
}
@Override
public EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
public EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, User user) throws ThingsboardException {
EdgeId edgeId = edge.getId();
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edgeId));
try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId,
edgeId, savedEntityView, actionType, user, savedEntityView.getEntityId().toString(),
edgeId, savedEntityView, ActionType.ASSIGNED_TO_EDGE, user, savedEntityView.getEntityId().toString(),
edgeId.toString(), edge.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
actionType, user, e, entityViewId.toString(), edgeId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
ActionType.ASSIGNED_TO_EDGE, user, e, entityViewId.toString(), edgeId.toString());
throw e;
}
}
@Override
public EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView,
Edge edge, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
Edge edge, User user) throws ThingsboardException {
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, user, entityViewId.toString(),
edgeId, entityView, ActionType.UNASSIGNED_FROM_EDGE, user, entityViewId.toString(),
edgeId.toString(), edge.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null,
actionType, user, e, entityViewId.toString(), edgeId.toString());
throw handleException(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, SecurityUser user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
try {
EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customer.getId(), savedEntityView,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customer.getId().toString(), customer.getName());
ActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customer.getId().toString(), customer.getName());
return savedEntityView;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null,
actionType, user, e, entityViewId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
ActionType.UNASSIGNED_FROM_CUSTOMER, user, e, entityViewId.toString());
throw e;
}
}
@Override
public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) {
Map<EntityId, List<EntityView>> localCacheByTenant = localCache.computeIfAbsent(tenantId, (k) -> new ConcurrentReferenceHashMap<>());
List<EntityView> fromLocalCache = localCacheByTenant.get(entityId);
if (fromLocalCache != null) {
return Futures.immediateFuture(fromLocalCache);
}
ListenableFuture<List<EntityView>> future = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId);
return Futures.transform(future, (entityViewList) -> {
localCacheByTenant.put(entityId, entityViewList);
return entityViewList;
}, MoreExecutors.directExecutor());
}
@Override
public void onComponentLifecycleMsg(ComponentLifecycleMsg componentLifecycleMsg) {
Map<EntityId, List<EntityView>> localCacheByTenant = localCache.computeIfAbsent(componentLifecycleMsg.getTenantId(), (k) -> new ConcurrentReferenceHashMap<>());
EntityViewId entityViewId = new EntityViewId(componentLifecycleMsg.getEntityId().getId());
deleteOldCacheValue(localCacheByTenant, entityViewId);
if (componentLifecycleMsg.getEvent() != ComponentLifecycleEvent.DELETED) {
EntityView entityView = entityViewService.findEntityViewById(componentLifecycleMsg.getTenantId(), entityViewId);
if (entityView != null) {
localCacheByTenant.remove(entityView.getEntityId());
}
}
}
private void deleteOldCacheValue(Map<EntityId, List<EntityView>> localCacheByTenant, EntityViewId entityViewId) {
for (var entry : localCacheByTenant.entrySet()) {
EntityView toDelete = null;
for (EntityView view : entry.getValue()) {
if (entityViewId.equals(view.getId())) {
toDelete = view;
break;
}
}
if (toDelete != null) {
entry.getValue().remove(toDelete);
break;
}
}
}
private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, SecurityUser user) throws ThingsboardException {
private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, User user) throws ThingsboardException {
EntityViewId entityId = entityView.getId();
if (keys != null && !keys.isEmpty()) {
ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getTenantId(), entityView.getEntityId(), scope, keys);
@ -221,8 +283,8 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
long lastUpdateTs = attributeKvEntry.getLastUpdateTs();
return startTime == 0 && endTime == 0 ||
(endTime == 0 && startTime < lastUpdateTs) ||
(startTime == 0 && endTime > lastUpdateTs)
? true : startTime < lastUpdateTs && endTime > lastUpdateTs;
(startTime == 0 && endTime > lastUpdateTs) ||
(startTime < lastUpdateTs && endTime > lastUpdateTs);
}).collect(Collectors.toList());
tsSubService.saveAndNotify(entityView.getTenantId(), entityId, scope, attributes, new FutureCallback<Void>() {
@Override
@ -251,7 +313,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
}
}
private ListenableFuture<List<Void>> copyLatestFromEntityToEntityView(EntityView entityView, SecurityUser user) {
private ListenableFuture<List<Void>> copyLatestFromEntityToEntityView(TenantId tenantId, EntityView entityView) {
EntityViewId entityId = entityView.getId();
List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ?
entityView.getKeys().getTimeseries() : Collections.emptyList();
@ -259,7 +321,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs();
ListenableFuture<List<String>> keysFuture;
if (keys.isEmpty()) {
keysFuture = Futures.transform(tsService.findAllLatest(user.getTenantId(),
keysFuture = Futures.transform(tsService.findAllLatest(tenantId,
entityView.getEntityId()), latest -> latest.stream().map(TsKvEntry::getKey).collect(Collectors.toList()), MoreExecutors.directExecutor());
} else {
keysFuture = Futures.immediateFuture(keys);
@ -267,7 +329,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
ListenableFuture<List<TsKvEntry>> latestFuture = Futures.transformAsync(keysFuture, fetchKeys -> {
List<ReadTsKvQuery> queries = fetchKeys.stream().filter(key -> !isBlank(key)).map(key -> new BaseReadTsKvQuery(key, startTs, endTs, 1, "DESC")).collect(Collectors.toList());
if (!queries.isEmpty()) {
return tsService.findAll(user.getTenantId(), entityView.getEntityId(), queries);
return tsService.findAll(tenantId, entityView.getEntityId(), queries);
} else {
return Futures.immediateFuture(null);
}
@ -288,7 +350,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
}, MoreExecutors.directExecutor());
}
private ListenableFuture<Void> deleteAttributesFromEntityView(EntityView entityView, String scope, List<String> keys, SecurityUser user) {
private ListenableFuture<Void> deleteAttributesFromEntityView(EntityView entityView, String scope, List<String> keys, User user) {
EntityViewId entityId = entityView.getId();
SettableFuture<Void> resultFuture = SettableFuture.create();
if (keys != null && !keys.isEmpty()) {
@ -319,7 +381,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
return resultFuture;
}
private ListenableFuture<Void> deleteLatestFromEntityView(EntityView entityView, List<String> keys, SecurityUser user) {
private ListenableFuture<Void> deleteLatestFromEntityView(EntityView entityView, List<String> keys, User user) {
EntityViewId entityId = entityView.getId();
SettableFuture<Void> resultFuture = SettableFuture.create();
if (keys != null && !keys.isEmpty()) {
@ -337,7 +399,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
@Override
public void onFailure(Throwable t) {
try {
logTimeseriesDeleted(entityView.getTenantId(),user, entityId, keys, t);
logTimeseriesDeleted(entityView.getTenantId(), user, entityId, keys, t);
} catch (ThingsboardException e) {
log.error("Failed to log timeseries delete", e);
}
@ -370,16 +432,16 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
return resultFuture;
}
private void logAttributesUpdated(TenantId tenantId, SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException {
notificationEntityService.notifyEntity(tenantId, entityId, null, null, ActionType.ATTRIBUTES_UPDATED, user, toException(e), scope, attributes);
private void logAttributesUpdated(TenantId tenantId, User user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException {
notificationEntityService.logEntityAction(tenantId, entityId, ActionType.ATTRIBUTES_UPDATED, user, toException(e), scope, attributes);
}
private void logAttributesDeleted(TenantId tenantId, SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) throws ThingsboardException {
notificationEntityService.notifyEntity(tenantId, entityId, null, null, ActionType.ATTRIBUTES_DELETED, user, toException(e), scope, keys);
private void logAttributesDeleted(TenantId tenantId, User user, EntityId entityId, String scope, List<String> keys, Throwable e) throws ThingsboardException {
notificationEntityService.logEntityAction(tenantId, entityId, ActionType.ATTRIBUTES_DELETED, user, toException(e), scope, keys);
}
private void logTimeseriesDeleted(TenantId tenantId, SecurityUser user, EntityId entityId, List<String> keys, Throwable e) throws ThingsboardException {
notificationEntityService.notifyEntity(tenantId, entityId, null, null, ActionType.TIMESERIES_DELETED, user, toException(e), keys);
private void logTimeseriesDeleted(TenantId tenantId, User user, EntityId entityId, List<String> keys, Throwable e) throws ThingsboardException {
notificationEntityService.logEntityAction(tenantId, entityId, ActionType.TIMESERIES_DELETED, user, toException(e), keys);
}
public static Exception toException(Throwable error) {

33
application/src/main/java/org/thingsboard/server/service/entitiy/entityView/TbEntityViewService.java → application/src/main/java/org/thingsboard/server/service/entitiy/entityview/TbEntityViewService.java

@ -13,35 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.entityView;
package org.thingsboard.server.service.entitiy.entityview;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
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.service.security.model.SecurityUser;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleListener;
public interface TbEntityViewService {
import java.util.List;
EntityView save(EntityView entityView, EntityView existingEntityView, SecurityUser user) throws ThingsboardException;
public interface TbEntityViewService extends ComponentLifecycleListener {
void delete (EntityView entity, SecurityUser user) throws ThingsboardException;
EntityView save(EntityView entityView, EntityView existingEntityView, User user) throws Exception;
EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer,
SecurityUser user) throws ThingsboardException;
void updateEntityViewAttributes(TenantId tenantId, EntityView savedEntityView, EntityView oldEntityView, User user) throws ThingsboardException;
void delete(EntityView entity, User user) throws ThingsboardException;
EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException;
EntityView assignEntityViewToPublicCustomer(TenantId tenantId, CustomerId customerId, Customer publicCustomer,
EntityViewId entityViewId, SecurityUser user) throws ThingsboardException;
EntityViewId entityViewId, User user) throws ThingsboardException;
EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, User user) throws ThingsboardException;
EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge,
SecurityUser user) throws ThingsboardException;
EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView, Edge edge, User user) throws ThingsboardException;
EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView,
Edge edge, SecurityUser user) throws ThingsboardException;
EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException;
EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer,
SecurityUser user) throws ThingsboardException;
ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId);
}

67
application/src/main/java/org/thingsboard/server/service/entitiy/otaPackageController/DefaultTbOtaPackageService.java → application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java

@ -13,24 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.otaPackageController;
package org.thingsboard.server.service.entitiy.ota;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.StringUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.nio.ByteBuffer;
@ -39,40 +40,31 @@ import java.nio.ByteBuffer;
@AllArgsConstructor
@Slf4j
public class DefaultTbOtaPackageService extends AbstractTbEntityService implements TbOtaPackageService {
private final OtaPackageService otaPackageService;
@Override
public OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, SecurityUser user) throws ThingsboardException {
TenantId tenantId = saveOtaPackageInfoRequest.getTenantId();
public OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, User user) throws ThingsboardException {
ActionType actionType = saveOtaPackageInfoRequest.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = saveOtaPackageInfoRequest.getTenantId();
try {
OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(new OtaPackageInfo(saveOtaPackageInfoRequest), saveOtaPackageInfoRequest.isUsesUrl());
notificationEntityService.notifyEntity(tenantId, savedOtaPackageInfo.getId(), savedOtaPackageInfo, null,
actionType, user, null);
boolean sendToEdge = savedOtaPackageInfo.hasUrl() || savedOtaPackageInfo.isHasData();
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackageInfo.getId(),
savedOtaPackageInfo, user, actionType, sendToEdge, null);
return savedOtaPackageInfo;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.OTA_PACKAGE), saveOtaPackageInfoRequest, null,
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), saveOtaPackageInfoRequest,
actionType, user, e);
throw handleException(e);
}
}
@Override
public void delete(OtaPackageInfo otaPackageInfo, SecurityUser user) throws ThingsboardException {
TenantId tenantId = otaPackageInfo.getTenantId();
OtaPackageId otaPackageId = otaPackageInfo.getId();
try {
otaPackageService.deleteOtaPackage(tenantId, otaPackageId);
notificationEntityService.notifyEntity(tenantId, otaPackageId, otaPackageInfo, null,
ActionType.DELETED, user, null, otaPackageInfo.getId().toString());
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.OTA_PACKAGE), null, null,
ActionType.DELETED, user, e, otaPackageInfo.getId().toString());
throw handleException(e);
throw e;
}
}
@Override
public OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm,
byte[] data, String filename, String contentType, SecurityUser user) throws ThingsboardException {
byte[] data, String filename, String contentType, User user) throws ThingsboardException {
TenantId tenantId = otaPackageInfo.getTenantId();
OtaPackageId otaPackageId = otaPackageInfo.getId();
try {
@ -95,13 +87,28 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
otaPackage.setData(ByteBuffer.wrap(data));
otaPackage.setDataSize((long) data.length);
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage);
notificationEntityService.notifyEntity(tenantId, savedOtaPackage.getId(), savedOtaPackage, null,
ActionType.UPDATED, user, null);
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackage.getId(),
savedOtaPackage, user, ActionType.UPDATED, true, null);
return savedOtaPackage;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.OTA_PACKAGE), null, null,
ActionType.UPDATED, user, e, otaPackageId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), ActionType.UPDATED,
user, e, otaPackageId.toString());
throw e;
}
}
@Override
public void delete(OtaPackageInfo otaPackageInfo, User user) throws ThingsboardException {
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());
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE),
ActionType.DELETED, user, e, otaPackageId.toString());
throw e;
}
}
}

15
application/src/main/java/org/thingsboard/server/service/entitiy/otaPackageController/TbOtaPackageService.java → application/src/main/java/org/thingsboard/server/service/entitiy/ota/TbOtaPackageService.java

@ -13,20 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.otaPackageController;
package org.thingsboard.server.service.entitiy.ota;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbOtaPackageService {
public interface TbOtaPackageService {
OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, SecurityUser user) throws ThingsboardException;
void delete(OtaPackageInfo otaPackageInfo, SecurityUser user) throws ThingsboardException;
OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, User user) throws ThingsboardException;
OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm,
byte[] data, String filename, String contentType, SecurityUser securityUser) throws ThingsboardException;
byte[] data, String filename, String contentType, User user) throws ThingsboardException;
void delete(OtaPackageInfo otaPackageInfo, User user) throws ThingsboardException;
}

60
application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java

@ -21,6 +21,7 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DeviceProfile;
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.page.PageLink;
@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.dao.device.DeviceProfileService;
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;
@ -46,12 +48,11 @@ import java.util.stream.Collectors;
@TbCoreComponent
@AllArgsConstructor
public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService {
private static final String MAIN = "Main";
private static final long DELETE_DELAY = 30;
private final QueueService queueService;
private final TbClusterService tbClusterService;
private final TbQueueAdmin tbQueueAdmin;
private final DeviceProfileService deviceProfileService;
private final SchedulerComponent scheduler;
@Override
@ -74,6 +75,8 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
onQueueUpdated(savedQueue, oldQueue);
}
notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), savedQueue.getId(), create ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return savedQueue;
}
@ -146,6 +149,8 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
}
}
}, DELETE_DELAY, TimeUnit.SECONDS);
notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), queue.getId(), EdgeEventActionType.DELETED);
}
@Override
@ -198,35 +203,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
}
tenantIds.forEach(tenantId -> {
Map<QueueId, List<DeviceProfile>> deviceProfileQueues;
if (oldTenantProfile != null && !newTenantProfile.getId().equals(oldTenantProfile.getId()) || !toRemove.isEmpty()) {
List<DeviceProfile> deviceProfiles = deviceProfileService.findDeviceProfiles(tenantId, new PageLink(Integer.MAX_VALUE)).getData();
deviceProfileQueues = deviceProfiles.stream()
.filter(dp -> dp.getDefaultQueueId() != null)
.collect(Collectors.groupingBy(DeviceProfile::getDefaultQueueId));
} else {
deviceProfileQueues = Collections.emptyMap();
}
Map<String, QueueId> createdQueues = toCreate.stream()
.map(key -> saveQueue(new Queue(tenantId, newQueues.get(key))))
.collect(Collectors.toMap(Queue::getName, Queue::getId));
// assigning created queues to device profiles instead of system queues
if (oldTenantProfile != null && !oldTenantProfile.isIsolatedTbRuleEngine()) {
deviceProfileQueues.forEach((queueId, list) -> {
Queue queue = queueService.findQueueById(TenantId.SYS_TENANT_ID, queueId);
QueueId queueIdToAssign = createdQueues.get(queue.getName());
if (queueIdToAssign == null) {
queueIdToAssign = createdQueues.get(MAIN);
}
for (DeviceProfile deviceProfile : list) {
deviceProfile.setDefaultQueueId(queueIdToAssign);
saveDeviceProfile(deviceProfile);
}
});
}
toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key))));
toUpdate.forEach(key -> {
Queue queueToUpdate = new Queue(tenantId, newQueues.get(key));
@ -234,9 +211,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
queueToUpdate.setId(foundQueue.getId());
queueToUpdate.setCreatedTime(foundQueue.getCreatedTime());
if (queueToUpdate.equals(foundQueue)) {
//Queue not changed
} else {
if (!queueToUpdate.equals(foundQueue)) {
saveQueue(queueToUpdate);
}
});
@ -244,26 +219,9 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
toRemove.forEach(q -> {
Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q);
QueueId queueIdForRemove = queue.getId();
if (deviceProfileQueues.containsKey(queueIdForRemove)) {
Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, q);
if (foundQueue == null || queue.equals(foundQueue)) {
foundQueue = queueService.findQueueByTenantIdAndName(tenantId, MAIN);
}
QueueId newQueueId = foundQueue.getId();
deviceProfileQueues.get(queueIdForRemove).stream()
.peek(dp -> dp.setDefaultQueueId(newQueueId))
.forEach(this::saveDeviceProfile);
}
deleteQueue(tenantId, queueIdForRemove);
});
});
}
//TODO: remove after implementing TbDeviceProfileService
private void saveDeviceProfile(DeviceProfile deviceProfile) {
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), savedDeviceProfile.getId(), ComponentLifecycleEvent.UPDATED);
}
}

57
application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java

@ -19,59 +19,58 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.entitiy.queue.TbQueueService;
import org.thingsboard.server.service.install.InstallScripts;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Service
@TbCoreComponent
@RequiredArgsConstructor
public class DefaultTbTenantService extends AbstractTbEntityService implements TbTenantService {
private final TenantService tenantService;
private final TbTenantProfileCache tenantProfileCache;
private final InstallScripts installScripts;
private final TbQueueService tbQueueService;
private final TenantProfileService tenantProfileService;
private final EntitiesVersionControlService versionControlService;
@Override
public Tenant save(Tenant tenant) throws ThingsboardException {
try {
boolean created = tenant.getId() == null;
Tenant oldTenant = !created ? tenantService.findTenantById(tenant.getId()) : null;
public Tenant save(Tenant tenant) throws Exception {
boolean created = tenant.getId() == null;
Tenant oldTenant = !created ? tenantService.findTenantById(tenant.getId()) : null;
Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant));
if (created) {
installScripts.createDefaultRuleChains(savedTenant.getId());
installScripts.createDefaultEdgeRuleChains(savedTenant.getId());
}
tenantProfileCache.evict(savedTenant.getId());
notificationEntityService.notifyCreateOruUpdateTenant(savedTenant, created ?
ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null;
TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId());
tbQueueService.updateQueuesByTenants(Collections.singletonList(savedTenant.getTenantId()), newTenantProfile, oldTenantProfile);
return savedTenant;
} catch (Exception e) {
throw handleException(e);
Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant));
if (created) {
installScripts.createDefaultRuleChains(savedTenant.getId());
installScripts.createDefaultEdgeRuleChains(savedTenant.getId());
}
tenantProfileCache.evict(savedTenant.getId());
notificationEntityService.notifyCreateOrUpdateTenant(savedTenant, created ?
ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null;
TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId());
tbQueueService.updateQueuesByTenants(Collections.singletonList(savedTenant.getTenantId()), newTenantProfile, oldTenantProfile);
return savedTenant;
}
@Override
public void delete(Tenant tenant) throws ThingsboardException {
try {
TenantId tenantId = tenant.getId();
tenantService.deleteTenant(tenantId);
tenantProfileCache.evict(tenantId);
notificationEntityService.notifyDeleteTenant(tenant);
} catch (Exception e) {
throw handleException(e);
}
public void delete(Tenant tenant) throws Exception {
TenantId tenantId = tenant.getId();
tenantService.deleteTenant(tenantId);
tenantProfileCache.evict(tenantId);
notificationEntityService.notifyDeleteTenant(tenant);
versionControlService.deleteVersionControlSettings(tenantId).get(1, TimeUnit.MINUTES);
}
}

5
application/src/main/java/org/thingsboard/server/service/entitiy/tenant/TbTenantService.java

@ -16,12 +16,11 @@
package org.thingsboard.server.service.entitiy.tenant;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.exception.ThingsboardException;
public interface TbTenantService {
Tenant save(Tenant tenant) throws ThingsboardException;
Tenant save(Tenant tenant) throws Exception;
void delete(Tenant tenant) throws ThingsboardException;
void delete(Tenant tenant) throws Exception;
}

25
application/src/main/java/org/thingsboard/server/service/entitiy/tenant_profile/DefaultTbTenantProfileService.java → application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/DefaultTbTenantProfileService.java

@ -13,16 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.tenant_profile;
package org.thingsboard.server.service.entitiy.tenant.profile;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.entitiy.queue.TbQueueService;
import java.util.List;
@ -31,20 +35,31 @@ import java.util.List;
@Service
@TbCoreComponent
@AllArgsConstructor
public class DefaultTbTenantProfileService implements TbTenantProfileService {
public class DefaultTbTenantProfileService extends AbstractTbEntityService implements TbTenantProfileService {
private final TbQueueService tbQueueService;
private final TenantProfileService tenantProfileService;
private final TenantService tenantService;
private final TbTenantProfileCache tenantProfileCache;
@Override
public TenantProfile saveTenantProfile(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) {
TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(tenantId, tenantProfile);
public TenantProfile save(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) throws ThingsboardException {
TenantProfile savedTenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(tenantId, tenantProfile));
if (oldTenantProfile != null && savedTenantProfile.isIsolatedTbRuleEngine()) {
List<TenantId> 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);
return savedTenantProfile;
}
@Override
public void delete(TenantId tenantId, TenantProfile tenantProfile) throws ThingsboardException {
tenantProfileService.deleteTenantProfile(tenantId, tenantProfile.getId());
tbClusterService.onTenantProfileDelete(tenantProfile, null);
}
}

26
application/src/main/java/org/thingsboard/server/service/entitiy/tenant/profile/TbTenantProfileService.java

@ -0,0 +1,26 @@
/**
* Copyright © 2016-2022 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.tenant.profile;
import org.thingsboard.server.common.data.TenantProfile;
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;
}

22
application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java

@ -28,9 +28,9 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import javax.servlet.http.HttpServletRequest;
@ -44,12 +44,13 @@ import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATT
@Slf4j
public class DefaultUserService extends AbstractTbEntityService implements TbUserService {
private final UserService userService;
private final MailService mailService;
private final SystemSecurityService systemSecurityService;
@Override
public User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail,
HttpServletRequest request, SecurityUser user) throws ThingsboardException {
HttpServletRequest request, User user) throws ThingsboardException {
ActionType actionType = tbUser.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
try {
boolean sendEmail = tbUser.getId() == null && sendActivationMail;
@ -71,25 +72,24 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
savedUser, user, actionType, true, null);
return savedUser;
} catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.USER),
tbUser, user, actionType, false, e);
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), tbUser, actionType, user, e);
throw e;
}
}
@Override
public void delete(TenantId tenantId, CustomerId customerId, User tbUser, SecurityUser user) throws ThingsboardException {
public void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException {
UserId userId = tbUser.getId();
try {
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, userId);
userService.deleteUser(tenantId, userId);
notificationEntityService.notifyDeleteEntity(tenantId, userId, tbUser, customerId,
ActionType.DELETED, relatedEdgeIds, user, userId.toString());
ActionType.DELETED, relatedEdgeIds, user, userId.toString());
} catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.USER),
null, user, ActionType.DELETED, false, e, userId.toString());
throw handleException(e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER),
ActionType.DELETED, user, e, userId.toString());
throw e;
}
}
}

5
application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java

@ -19,12 +19,11 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
import javax.servlet.http.HttpServletRequest;
public interface TbUserService {
User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail, HttpServletRequest request, SecurityUser user) throws ThingsboardException;
User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail, HttpServletRequest request, User user) throws ThingsboardException;
void delete (TenantId tenantId, CustomerId customerId, User tbUser, SecurityUser user) throws ThingsboardException;
void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException;
}

33
application/src/main/java/org/thingsboard/server/service/entitiy/widgetsBundle/DefaultWidgetsBundleService.java → application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java

@ -13,41 +13,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.entitiy.widgetsBundle;
package org.thingsboard.server.service.entitiy.widgets.bundle;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
@Service
@TbCoreComponent
@AllArgsConstructor
public class DefaultWidgetsBundleService extends AbstractTbEntityService implements TbWidgetsBundleService{
public class DefaultWidgetsBundleService extends AbstractTbEntityService implements TbWidgetsBundleService {
private final WidgetsBundleService widgetsBundleService;
@Override
public WidgetsBundle save(WidgetsBundle widgetsBundle, SecurityUser user) throws ThingsboardException {
try {
public WidgetsBundle save(WidgetsBundle widgetsBundle, User user) throws Exception {
WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), savedWidgetsBundle.getId(),
widgetsBundle.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
autoCommit(user, savedWidgetsBundle.getId());
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), savedWidgetsBundle.getId(),
widgetsBundle.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return savedWidgetsBundle;
} catch (Exception e) {
throw handleException(e);
}
}
@Override
public void delete(WidgetsBundle widgetsBundle, SecurityUser user) throws ThingsboardException {
try {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId());
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), widgetsBundle.getId(),
EdgeEventActionType.DELETED);
} catch (Exception e) {
throw handleException(e);
}
public void delete(WidgetsBundle widgetsBundle) throws ThingsboardException {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId());
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), widgetsBundle.getId(),
EdgeEventActionType.DELETED);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save