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> <groupId>org.thingsboard.common</groupId>
<artifactId>cluster-api</artifactId> <artifactId>cluster-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>version-control</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.thingsboard.rule-engine</groupId> <groupId>org.thingsboard.rule-engine</groupId>
<artifactId>rule-engine-components</artifactId> <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="org.thingsboard.server" level="INFO" />
<logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" /> <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"> <root level="INFO">
<appender-ref ref="fileLogAppender"/> <appender-ref ref="fileLogAppender"/>

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

@ -14,6 +14,31 @@
-- limitations under the License. -- 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 ( CREATE TABLE IF NOT EXISTS queue (
id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY, id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY,
created_time bigint NOT NULL, 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), user_id uuid UNIQUE NOT NULL CONSTRAINT fk_user_auth_settings_user_id REFERENCES tb_user(id),
two_fa_settings varchar 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.dao",
"org.thingsboard.server.common.stats", "org.thingsboard.server.common.stats",
"org.thingsboard.server.common.transport.config.ssl", "org.thingsboard.server.common.transport.config.ssl",
"org.thingsboard.server.cache"}) "org.thingsboard.server.cache",
"org.thingsboard.server.springfox"
})
public class ThingsboardInstallApplication { public class ThingsboardInstallApplication {
private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; 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.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.tools.TbRateLimits; 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.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.audit.AuditLogService; 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.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.usagestats.TbApiUsageClient; 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.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService; 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.DbCallbackExecutorService;
import org.thingsboard.server.service.executors.ExternalCallExecutorService; import org.thingsboard.server.service.executors.ExternalCallExecutorService;
import org.thingsboard.server.service.executors.SharedEventLoopGroupService; import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
@ -220,6 +221,11 @@ public class ActorSystemContext {
@Getter @Getter
private EntityViewService entityViewService; private EntityViewService entityViewService;
@Lazy
@Autowired(required = false)
@Getter
private TbEntityViewService tbEntityViewService;
@Autowired @Autowired
@Getter @Getter
private TelemetrySubscriptionService tsSubService; private TelemetrySubscriptionService tsSubService;
@ -502,13 +508,8 @@ public class ActorSystemContext {
return partitionService.resolve(serviceType, tenantId, entityId); 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) { 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() { public String getServiceId() {

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

@ -162,18 +162,11 @@ class DefaultTbContext implements TbContext {
} }
@Override @Override
@Deprecated
public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure) { public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName); TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueue(tpi, tbMsg, onFailure, onSuccess); 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) { private void enqueue(TopicPartitionInfo tpi, TbMsg tbMsg, Consumer<Throwable> onFailure, Runnable onSuccess) {
if (!tbMsg.isValid()) { if (!tbMsg.isValid()) {
log.trace("[{}] Skip invalid message: {}", getTenantId(), tbMsg); log.trace("[{}] Skip invalid message: {}", getTenantId(), tbMsg);
@ -223,35 +216,30 @@ class DefaultTbContext implements TbContext {
} }
@Override @Override
public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) { public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId); TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueueForTellNext(tpi, queueId, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure); enqueueForTellNext(tpi, queueName, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
} }
@Override @Override
public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) { public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId); TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueueForTellNext(tpi, queueId, tbMsg, relationTypes, null, onSuccess, onFailure); enqueueForTellNext(tpi, queueName, tbMsg, relationTypes, null, onSuccess, onFailure);
}
private TopicPartitionInfo resolvePartition(TbMsg tbMsg, QueueId queueId) {
return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueId, getTenantId(), tbMsg.getOriginator());
} }
@Deprecated
private TopicPartitionInfo resolvePartition(TbMsg tbMsg, String queueName) { private TopicPartitionInfo resolvePartition(TbMsg tbMsg, String queueName) {
return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator()); return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
} }
private TopicPartitionInfo resolvePartition(TbMsg tbMsg) { 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) { 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()) { if (!source.isValid()) {
log.trace("[{}] Skip invalid message: {}", getTenantId(), source); log.trace("[{}] Skip invalid message: {}", getTenantId(), source);
if (onFailure != null) { if (onFailure != null) {
@ -261,7 +249,7 @@ class DefaultTbContext implements TbContext {
} }
RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId(); RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId();
RuleNodeId ruleNodeId = nodeCtx.getSelf().getId(); 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() TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder()
.setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) .setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
.setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
@ -320,13 +308,13 @@ class DefaultTbContext implements TbContext {
} }
@Override @Override
public TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data) { public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueId, type, originator, null, metaData, data); return newMsg(queueName, type, originator, null, metaData, data);
} }
@Override @Override
public TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { public TbMsg newMsg(String queueName, 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()); return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
} }
@Override @Override
@ -340,17 +328,17 @@ class DefaultTbContext implements TbContext {
public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) {
RuleChainId ruleChainId = null; RuleChainId ruleChainId = null;
QueueId queueId = null; String queueName = null;
if (device.getDeviceProfileId() != null) { if (device.getDeviceProfileId() != null) {
DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId()); DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId());
if (deviceProfile == null) { if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", device.getDeviceProfileId()); log.warn("[{}] Device profile is null!", device.getDeviceProfileId());
} else { } else {
ruleChainId = deviceProfile.getDefaultRuleChainId(); 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) { public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) {
@ -359,7 +347,7 @@ class DefaultTbContext implements TbContext {
public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) { public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) {
RuleChainId ruleChainId = null; RuleChainId ruleChainId = null;
QueueId queueId = null; String queueName = null;
if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) { if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) {
DeviceId deviceId = new DeviceId(alarm.getOriginator().getId()); DeviceId deviceId = new DeviceId(alarm.getOriginator().getId());
DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId);
@ -367,10 +355,10 @@ class DefaultTbContext implements TbContext {
log.warn("[{}] Device profile is null!", deviceId); log.warn("[{}] Device profile is null!", deviceId);
} else { } else {
ruleChainId = deviceProfile.getDefaultRuleChainId(); 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 @Override
@ -382,9 +370,9 @@ class DefaultTbContext implements TbContext {
return entityActionMsg(entity, id, ruleNodeId, action, null, null); 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 { 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) { } catch (JsonProcessingException | IllegalArgumentException e) {
throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + 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 { try {
checkComponentStateActive(msg); checkComponentStateActive(msg);
EntityId entityId = msg.getOriginator(); 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); List<RuleNodeRelation> ruleNodeRelations = nodeRoutes.get(originatorNodeId);
if (ruleNodeRelations == null) { // When unchecked, this will cause NullPointerException when rule node doesn't exist anymore 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; 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.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.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean; 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.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException; 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.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
@ -35,42 +39,40 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@Slf4j
@Component @Component
public class RateLimitProcessingFilter extends GenericFilterBean { 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 @Autowired
private ThingsboardErrorResponseHandler errorResponseHandler; private ThingsboardErrorResponseHandler errorResponseHandler;
private ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>(); @Autowired
private ConcurrentMap<CustomerId, TbRateLimits> perCustomerLimits = new ConcurrentHashMap<>(); @Lazy
private TbTenantProfileCache tenantProfileCache;
private final ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>();
private final ConcurrentMap<CustomerId, TbRateLimits> perCustomerLimits = new ConcurrentHashMap<>();
@Override @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
if (user != null && !user.isSystemAdmin()) { if (user != null && !user.isSystemAdmin()) {
if (perTenantLimitsEnabled) { var profile = tenantProfileCache.get(user.getTenantId());
TbRateLimits rateLimits = perTenantLimits.computeIfAbsent(user.getTenantId(), id -> new TbRateLimits(perTenantLimitsConfiguration)); if (profile == null) {
if (!rateLimits.tryConsume()) { log.debug("[{}] Failed to lookup tenant profile", user.getTenantId());
errorResponseHandler.handle(new TbRateLimitsException(EntityType.TENANT), (HttpServletResponse) response); errorResponseHandler.handle(new BadCredentialsException("Failed to lookup tenant profile"), (HttpServletResponse) response);
return; return;
} }
var profileConfiguration = profile.getDefaultProfileConfiguration();
if (!checkRateLimits(user.getTenantId(), profileConfiguration.getTenantServerRestLimitsConfiguration(), perTenantLimits, response)) {
return;
} }
if (perCustomerLimitsEnabled && user.isCustomerUser()) { if (user.isCustomerUser()) {
TbRateLimits rateLimits = perCustomerLimits.computeIfAbsent(user.getCustomerId(), id -> new TbRateLimits(perCustomerLimitsConfiguration)); if (!checkRateLimits(user.getCustomerId(), profileConfiguration.getCustomerServerRestLimitsConfiguration(), perCustomerLimits, response)) {
if (!rateLimits.tryConsume()) {
errorResponseHandler.handle(new TbRateLimitsException(EntityType.CUSTOMER), (HttpServletResponse) response);
return; return;
} }
} }
@ -78,6 +80,25 @@ public class RateLimitProcessingFilter extends GenericFilterBean {
chain.doFilter(request, response); 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() { protected SecurityUser getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) { 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.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager; 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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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.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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; 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.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter; import org.springframework.web.filter.CorsFilter;
import org.thingsboard.server.dao.audit.AuditLogLevelFilter;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration; import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -63,7 +63,7 @@ import java.util.List;
@EnableGlobalMethodSecurity(prePostEnabled=true) @EnableGlobalMethodSecurity(prePostEnabled=true)
@Order(SecurityProperties.BASIC_AUTH_ORDER) @Order(SecurityProperties.BASIC_AUTH_ORDER)
@TbCoreComponent @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 = "X-Authorization";
public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization"; public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization";
@ -161,16 +161,15 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
} }
@Bean @Bean
@Override public AuthenticationManager authenticationManager(ObjectPostProcessor<Object> objectPostProcessor) throws Exception {
public AuthenticationManager authenticationManagerBean() throws Exception { DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
return super.authenticationManagerBean(); .postProcess(new DefaultAuthenticationEventPublisher());
} var auth = new AuthenticationManagerBuilder(objectPostProcessor);
auth.authenticationEventPublisher(eventPublisher);
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(restAuthenticationProvider); auth.authenticationProvider(restAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider); auth.authenticationProvider(jwtAuthenticationProvider);
auth.authenticationProvider(refreshTokenAuthenticationProvider); auth.authenticationProvider(refreshTokenAuthenticationProvider);
return auth.build();
} }
@Bean @Bean
@ -181,13 +180,20 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
@Autowired @Autowired
private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver; private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver;
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { @Order(0)
http.authorizeHttpRequests((authorizeHttpRequests) -> SecurityFilterChain resources(HttpSecurity http) throws Exception {
authorizeHttpRequests http
.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**") .requestMatchers((matchers) -> matchers.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**"))
.permitAll() .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() http.headers().cacheControl().and().frameOptions().disable()
.and() .and()
.cors() .cors()
@ -229,6 +235,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
.successHandler(oauth2AuthenticationSuccessHandler) .successHandler(oauth2AuthenticationSuccessHandler)
.failureHandler(oauth2AuthenticationFailureHandler); .failureHandler(oauth2AuthenticationFailureHandler);
} }
return http.build();
} }
@Bean @Bean
@ -242,5 +249,4 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
return new CorsFilter(source); return new CorsFilter(source);
} }
} }
} }

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

@ -16,16 +16,16 @@
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.node.ObjectNode; 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.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.context.request.async.DeferredResult;
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.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.AdminSettings; 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.id.TenantId;
import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest; 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.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.security.system.SystemSecurityService; 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 org.thingsboard.server.service.update.UpdateService;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.*;
@RestController @RestController
@TbCoreComponent @TbCoreComponent
@ -60,6 +64,12 @@ public class AdminController extends BaseController {
@Autowired @Autowired
private SystemSecurityService systemSecurityService; private SystemSecurityService systemSecurityService;
@Autowired
private EntitiesVersionControlService versionControlService;
@Autowired
private TbAutoCommitSettingsService autoCommitSettingsService;
@Autowired @Autowired
private UpdateService updateService; private UpdateService updateService;
@ -96,6 +106,7 @@ public class AdminController extends BaseController {
@RequestBody AdminSettings adminSettings) throws ThingsboardException { @RequestBody AdminSettings adminSettings) throws ThingsboardException {
try { try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE); accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
adminSettings.setTenantId(getTenantId());
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings)); adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
if (adminSettings.getKey().equals("mail")) { if (adminSettings.getKey().equals("mail")) {
mailService.updateMailConfiguration(); 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)", @ApiOperation(value = "Check for new Platform Releases (checkUpdates)",
notes = "Check notifications about new platform releases. " notes = "Check notifications about new platform releases. "
+ SYSTEM_AUTHORITY_PARAGRAPH) + 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'. " + "\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. " + "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 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) , produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm", method = RequestMethod.POST) @RequestMapping(value = "/alarm", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Alarm saveAlarm(@ApiParam(value = "A JSON value representing the alarm.") @RequestBody Alarm alarm) throws ThingsboardException { 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); checkEntity(alarm.getId(), alarm, Resource.ALARM);
return tbAlarmService.save(alarm, getCurrentUser()); return tbAlarmService.save(alarm, getCurrentUser());
} }
@ -144,13 +146,9 @@ public class AlarmController extends BaseController {
@ResponseBody @ResponseBody
public Boolean deleteAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException { public Boolean deleteAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId); checkParameter(ALARM_ID, strAlarmId);
try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.DELETE);
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); return tbAlarmService.delete(alarm, getCurrentUser());
return tbAlarmService.delete(alarm, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
} }
@ApiOperation(value = "Acknowledge Alarm (ackAlarm)", @ApiOperation(value = "Acknowledge Alarm (ackAlarm)",
@ -160,11 +158,11 @@ public class AlarmController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST) @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK) @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); checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
tbAlarmService.ack(alarm, getCurrentUser()); tbAlarmService.ack(alarm, getCurrentUser()).get();
} }
@ApiOperation(value = "Clear Alarm (clearAlarm)", @ApiOperation(value = "Clear Alarm (clearAlarm)",
@ -174,11 +172,11 @@ public class AlarmController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST) @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK) @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); checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
tbAlarmService.clear(alarm, getCurrentUser()); tbAlarmService.clear(alarm, getCurrentUser()).get();
} }
@ApiOperation(value = "Get Alarms (getAlarms)", @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.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.asset.AssetBulkImportService; 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.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.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; 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 + 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. " + "The newly created Asset id will be present in the response. " +
"Specify existing Asset id to update the asset. " + "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')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset", method = RequestMethod.POST) @RequestMapping(value = "/asset", method = RequestMethod.POST)
@ResponseBody @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())) { if (TB_SERVICE_QUEUE.equals(asset.getType())) {
throw new ThingsboardException("Unable to save asset with type " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS); 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); checkEntity(asset.getId(), asset, Resource.ASSET);
return tbAssetService.save(asset, getCurrentUser()); return tbAssetService.save(asset, getCurrentUser());
} }
@ -157,15 +159,11 @@ public class AssetController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE) @RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK) @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); checkParameter(ASSET_ID, strAssetId);
try { AssetId assetId = new AssetId(toUUID(strAssetId));
AssetId assetId = new AssetId(toUUID(strAssetId)); Asset asset = checkAssetId(assetId, Operation.DELETE);
Asset asset = checkAssetId(assetId, Operation.DELETE); tbAssetService.delete(asset, getCurrentUser()).get();
tbAssetService.delete(asset, getCurrentUser()).get();
} catch (Exception e) {
throw handleException(e);
}
} }
@ApiOperation(value = "Assign asset to customer (assignAssetToCustomer)", @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; package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; 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.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; 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.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler; 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.cluster.TbClusterService;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; 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.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo; 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.HasTenantId;
import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo; 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.alarm.AlarmInfo;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetInfo; 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.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType; 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.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.queue.Queue; 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.rpc.Rpc;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType; 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.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService; 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.ota.OtaPackageStateService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.resource.TbResourceService; 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.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.state.DeviceStateService; 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.AlarmSubscriptionService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
@ -276,11 +279,14 @@ public abstract class BaseController {
protected EdgeRpcService edgeGrpcService; protected EdgeRpcService edgeGrpcService;
@Autowired @Autowired
protected EntityActionService entityActionService; protected TbNotificationEntityService notificationEntityService;
@Autowired @Autowired
protected QueueService queueService; protected QueueService queueService;
@Autowired
protected EntitiesVersionControlService vcService;
@Value("${server.log_controller_error_stack_trace}") @Value("${server.log_controller_error_stack_trace}")
@Getter @Getter
private boolean logControllerErrorStackTrace; private boolean logControllerErrorStackTrace;
@ -341,6 +347,8 @@ public abstract class BaseController {
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else if (exception instanceof MessagingException) { } else if (exception instanceof MessagingException) {
return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL);
} else if (exception instanceof AsyncRequestTimeoutException) {
return new ThingsboardException("Request timeout", ThingsboardErrorCode.GENERAL);
} else { } else {
return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL); return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL);
} }
@ -882,95 +890,20 @@ public abstract class BaseController {
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); 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) { public static Exception toException(Throwable error) {
return error != null ? (Exception.class.isInstance(error) ? (Exception) error : new Exception(error)) : null; 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) { 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) { 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) { private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action); tbClusterService.sendNotificationMsgToEdge(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;
} }
protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException { protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException {
@ -989,4 +922,20 @@ public abstract class BaseController {
return MediaType.APPLICATION_OCTET_STREAM; 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. " + 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. " + "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. "; "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 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 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'"; 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 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_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 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 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_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."; 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 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_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_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_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_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"; 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_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 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_START = "```json\n";
protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; protected static final String MARKDOWN_CODE_BLOCK_END = "\n```";
protected static final String EVENT_ERROR_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + 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 + 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. " + "The newly created Customer Id will be present in the response. " +
"Specify existing Customer Id to update the Customer. " + "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')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer", method = RequestMethod.POST) @RequestMapping(value = "/customer", method = RequestMethod.POST)
@ResponseBody @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()); customer.setTenantId(getTenantId());
checkEntity(customer.getId(), customer, Resource.CUSTOMER); checkEntity(customer.getId(), customer, Resource.CUSTOMER);
return tbCustomerService.save(customer, getCurrentUser()); return tbCustomerService.save(customer, getCurrentUser());
@ -160,11 +162,7 @@ public class CustomerController extends BaseController {
checkParameter(CUSTOMER_ID, strCustomerId); checkParameter(CUSTOMER_ID, strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.DELETE); Customer customer = checkCustomerId(customerId, Operation.DELETE);
try { tbCustomerService.delete(customer, getCurrentUser());
tbCustomerService.delete(customer, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
} }
@ApiOperation(value = "Get Tenant Customers (getCustomers)", @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. " + "The newly created Dashboard id will be present in the response. " +
"Specify existing Dashboard id to update the dashboard. " + "Specify existing Dashboard id to update the dashboard. " +
"Referencing non-existing dashboard Id will cause 'Not Found' error. " + "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, TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE) consumes = MediaType.APPLICATION_JSON_VALUE)
@ -180,7 +181,7 @@ public class DashboardController extends BaseController {
@ResponseBody @ResponseBody
public Dashboard saveDashboard( public Dashboard saveDashboard(
@ApiParam(value = "A JSON value representing the dashboard.") @ApiParam(value = "A JSON value representing the dashboard.")
@RequestBody Dashboard dashboard) throws ThingsboardException { @RequestBody Dashboard dashboard) throws Exception {
dashboard.setTenantId(getTenantId()); dashboard.setTenantId(getTenantId());
checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD); checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD);
return tbDashboardService.save(dashboard, getCurrentUser()); return tbDashboardService.save(dashboard, getCurrentUser());
@ -219,8 +220,8 @@ public class DashboardController extends BaseController {
Customer customer = checkCustomerId(customerId, Operation.READ); Customer customer = checkCustomerId(customerId, Operation.READ);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
return tbDashboardService.assignDashboardToCustomer(dashboardId, customer, getCurrentUser()); return tbDashboardService.assignDashboardToCustomer(dashboard, customer, getCurrentUser());
} }
@ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)", @ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)",
@ -261,7 +262,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId); checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); 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()); return tbDashboardService.updateDashboardCustomers(dashboard, customerIds, getCurrentUser());
} }
@ -281,7 +282,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId); checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); 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()); return tbDashboardService.addDashboardCustomers(dashboard, customerIds, getCurrentUser());
} }
@ -301,7 +302,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId); checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); 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()); return tbDashboardService.removeDashboardCustomers(dashboard, customerIds, getCurrentUser());
} }
@ -321,8 +322,8 @@ public class DashboardController extends BaseController {
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId); checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
return tbDashboardService.assignDashboardToPublicCustomer(dashboardId, getCurrentUser()); return tbDashboardService.assignDashboardToPublicCustomer(dashboard, getCurrentUser());
} }
@ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)", @ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)",
@ -631,7 +632,7 @@ public class DashboardController extends BaseController {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId, Operation.READ); checkDashboardId(dashboardId, Operation.READ);
return tbDashboardService.asignDashboardToEdge(dashboardId, edge, getCurrentUser()); return tbDashboardService.asignDashboardToEdge(getTenantId(), dashboardId, edge, getCurrentUser());
} }
@ApiOperation(value = "Unassign dashboard from edge (unassignDashboardFromEdge)", @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<>(); Set<CustomerId> customerIds = new HashSet<>();
if (strCustomerIds != null) { if (strCustomerIds != null) {
for (String strCustomerId : strCustomerIds) { for (String strCustomerId : strCustomerIds) {
CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); customerIds.add(new CustomerId(UUID.fromString(strCustomerId)));
if (dashboard.isAssignedToCustomer(customerId)) {
customerIds.add(customerId);
}
} }
} }
return customerIds; 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.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService; 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.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.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; 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. " + "The newly created device id will be present in the response. " +
"Specify existing Device id to update the device. " + "Specify existing Device id to update the device. " +
"Referencing non-existing device Id will cause 'Not Found' error." + "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." "\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) "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')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device", method = RequestMethod.POST) @RequestMapping(value = "/device", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Device saveDevice(@ApiParam(value = "A JSON value representing the device.") @RequestBody Device device, 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. " + @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.setTenantId(getCurrentUser().getTenantId());
Device oldDevice = null; Device oldDevice = null;
if (device.getId() != null) { if (device.getId() != null) {
@ -173,7 +174,7 @@ public class DeviceController extends BaseController {
} else { } else {
checkEntity(null, device, Resource.DEVICE); 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 ", @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. " + "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" + "You may find the example of LwM2M device and RPK credentials below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN + 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) TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST) @RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST)
@ -191,25 +193,20 @@ public class DeviceController extends BaseController {
DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials()); DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials());
device.setTenantId(getCurrentUser().getTenantId()); device.setTenantId(getCurrentUser().getTenantId());
checkEntity(device.getId(), device, Resource.DEVICE); checkEntity(device.getId(), device, Resource.DEVICE);
return tbDeviceService.saveDeviceWithCredentials(getTenantId(), device, credentials, getCurrentUser()); return tbDeviceService.saveDeviceWithCredentials(device, credentials, getCurrentUser());
} }
@ApiOperation(value = "Delete device (deleteDevice)", @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) 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')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE) @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK) @ResponseStatus(value = HttpStatus.OK)
public void deleteDevice(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) 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); checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId, Operation.DELETE); Device device = checkDeviceId(deviceId, Operation.DELETE);
try { tbDeviceService.delete(device, getCurrentUser()).get();
tbDeviceService.delete(device, getCurrentUser()).get();
} catch (Exception e) {
throw handleException(e);
}
} }
@ApiOperation(value = "Assign device to customer (assignDeviceToCustomer)", @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) public Device unassignDeviceFromCustomer(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId); checkParameter(DEVICE_ID, strDeviceId);
try { DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_CUSTOMER);
Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_CUSTOMER); if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { throw new IncorrectParameterException("Device isn't assigned to any customer!");
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()); return tbDeviceService.unassignDeviceFromCustomer(device, customer, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
} }
@ApiOperation(value = "Make device publicly available (assignDeviceToPublicCustomer)", @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); ListenableFuture<ClaimResult> future = tbDeviceService.claimDevice(tenantId, device, customerId, secretKey, user);
Futures.addCallback(future, new FutureCallback<ClaimResult>() { Futures.addCallback(future, new FutureCallback<>() {
@Override @Override
public void onSuccess(@Nullable ClaimResult result) { public void onSuccess(@Nullable ClaimResult result) {
HttpStatus status; 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") public DeferredResult<ResponseEntity> reClaimDevice(@ApiParam(value = "Unique name of the device which is going to be reclaimed")
@PathVariable(DEVICE_NAME) String deviceName) throws ThingsboardException { @PathVariable(DEVICE_NAME) String deviceName) throws ThingsboardException {
checkParameter(DEVICE_NAME, deviceName); checkParameter(DEVICE_NAME, deviceName);
try { final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId(); TenantId tenantId = user.getTenantId();
Device device = checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName)); Device device = checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES, accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES,
device.getId(), device); device.getId(), device);
ListenableFuture<ReclaimResult> result = tbDeviceService.reclaimDevice(tenantId, device, user); ListenableFuture<ReclaimResult> result = tbDeviceService.reclaimDevice(tenantId, device, user);
Futures.addCallback(result, new FutureCallback<>() { Futures.addCallback(result, new FutureCallback<>() {
@Override @Override
public void onSuccess(ReclaimResult reclaimResult) { public void onSuccess(ReclaimResult reclaimResult) {
deferredResult.setResult(new ResponseEntity(HttpStatus.OK)); deferredResult.setResult(new ResponseEntity(HttpStatus.OK));
} }
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
deferredResult.setErrorResult(t); deferredResult.setErrorResult(t);
} }
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
return deferredResult; return deferredResult;
} catch (Exception e) {
throw handleException(e);
}
} }
private String getSecretKey(ClaimRequest claimRequest) { 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.common.data.page.PageLink;
import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
@ -71,7 +71,7 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@Slf4j @Slf4j
public class DeviceProfileController extends BaseController { public class DeviceProfileController extends BaseController {
private final TbDeviceProfileService tbDeviceProfileService; private final TbDeviceProfileService tbDeviceProfileService;
@Autowired @Autowired
private TimeseriesService timeseriesService; private TimeseriesService timeseriesService;
@ -108,7 +108,7 @@ public class DeviceProfileController extends BaseController {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try { try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return checkNotNull(deviceProfileService.findDeviceProfileInfoById(getTenantId(), deviceProfileId)); return new DeviceProfileInfo(checkDeviceProfileId(deviceProfileId, Operation.READ));
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }
@ -191,6 +191,7 @@ public class DeviceProfileController extends BaseController {
"Specify existing device profile id to update the device profile. " + "Specify existing device profile id to update the device profile. " +
"Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE + "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 + "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, TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json", produces = "application/json",
consumes = "application/json") consumes = "application/json")
@ -199,7 +200,7 @@ public class DeviceProfileController extends BaseController {
@ResponseBody @ResponseBody
public DeviceProfile saveDeviceProfile( public DeviceProfile saveDeviceProfile(
@ApiParam(value = "A JSON value representing the device profile.") @ApiParam(value = "A JSON value representing the device profile.")
@RequestBody DeviceProfile deviceProfile) throws ThingsboardException { @RequestBody DeviceProfile deviceProfile) throws Exception {
deviceProfile.setTenantId(getTenantId()); deviceProfile.setTenantId(getTenantId());
checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
return tbDeviceProfileService.save(deviceProfile, getCurrentUser()); return tbDeviceProfileService.save(deviceProfile, getCurrentUser());
@ -219,7 +220,7 @@ public class DeviceProfileController extends BaseController {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE); DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE);
tbDeviceProfileService.delete(deviceProfile, getCurrentUser()); tbDeviceProfileService.delete(deviceProfile, getCurrentUser());
} }
@ApiOperation(value = "Make Device Profile Default (setDefaultDeviceProfile)", @ApiOperation(value = "Make Device Profile Default (setDefaultDeviceProfile)",
notes = "Marks device profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH, 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.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; 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.Customer;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.edge.Edge; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService; import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.importing.BulkImportRequest; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult; 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.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; 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. " + "The newly created edge id will be present in the response. " +
"Specify existing Edge id to update the edge. " + "Specify existing Edge id to update the edge. " +
"Referencing non-existing Edge Id will cause 'Not Found' error." + "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." "\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, "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) produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST) @RequestMapping(value = "/edge", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true) public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true)
@RequestBody Edge edge) throws ThingsboardException { @RequestBody Edge edge) throws Exception {
TenantId tenantId = getCurrentUser().getTenantId(); TenantId tenantId = getTenantId();
edge.setTenantId(tenantId); edge.setTenantId(tenantId);
boolean created = edge.getId() == null; 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) public Edge setEdgeRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId, @PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true) @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(EDGE_ID, strEdgeId);
checkParameter("ruleChainId", strRuleChainId); checkParameter("ruleChainId", strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -557,7 +559,7 @@ public class EdgeController extends BaseController {
edgeId = checkNotNull(edgeId); edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId(); TenantId tenantId = user.getTenantId();
return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId); return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId, TbRuleChainInputNode.class.getName());
} catch (Exception e) { } catch (Exception e) {
throw handleException(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.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.queue.util.TbCoreComponent; 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 org.thingsboard.server.service.security.permission.Operation;
import java.util.List; import java.util.List;
@ -54,7 +55,7 @@ import static org.thingsboard.server.controller.ControllerConstants.RELATION_TYP
@RequiredArgsConstructor @RequiredArgsConstructor
public class EntityRelationController extends BaseController { public class EntityRelationController extends BaseController {
private final TbEntityRelationService tbEntityRelationService; private final TbEntityRelationService tbEntityRelationService;
public static final String TO_TYPE = "toType"; public static final String TO_TYPE = "toType";
public static final String FROM_ID = "fromId"; 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) public void saveRelation(@ApiParam(value = "A JSON value representing the relation.", required = true)
@RequestBody EntityRelation relation) throws ThingsboardException { @RequestBody EntityRelation relation) throws ThingsboardException {
checkNotNull(relation); checkNotNull(relation);
checkEntityId(relation.getFrom(), Operation.WRITE); checkCanCreateRelation(relation.getFrom());
checkEntityId(relation.getTo(), Operation.WRITE); checkCanCreateRelation(relation.getTo());
if (relation.getTypeGroup() == null) { if (relation.getTypeGroup() == null) {
relation.setTypeGroup(RelationTypeGroup.COMMON); relation.setTypeGroup(RelationTypeGroup.COMMON);
} }
tbEntityRelationService.save(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser()); tbEntityRelationService.save(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
} }
@ApiOperation(value = "Delete Relation (deleteRelation)", @ApiOperation(value = "Delete Relation (deleteRelation)",
@ -107,11 +108,11 @@ public class EntityRelationController extends BaseController {
checkParameter(TO_TYPE, strToType); checkParameter(TO_TYPE, strToType);
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(fromId, Operation.WRITE); checkCanCreateRelation(fromId);
checkEntityId(toId, Operation.WRITE); checkCanCreateRelation(toId);
RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
EntityRelation relation = new EntityRelation(fromId, toId, strRelationType, relationTypeGroup); EntityRelation relation = new EntityRelation(fromId, toId, strRelationType, relationTypeGroup);
tbEntityRelationService.delete(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser()); tbEntityRelationService.delete(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
} }
@ -127,7 +128,7 @@ public class EntityRelationController extends BaseController {
checkParameter("entityType", strType); checkParameter("entityType", strType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId);
checkEntityId(entityId, Operation.WRITE); checkEntityId(entityId, Operation.WRITE);
tbEntityRelationService.deleteRelations (getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser()); tbEntityRelationService.deleteRelations(getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser());
} }
@ApiOperation(value = "Get Relation (getRelation)", @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) { private <T extends EntityRelation> List<T> filterRelationsByReadPermission(List<T> relationsByQuery) {
return relationsByQuery.stream().filter(relationByQuery -> { return relationsByQuery.stream().filter(relationByQuery -> {
try { 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.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; 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)", @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) produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView", method = RequestMethod.POST) @RequestMapping(value = "/entityView", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public EntityView saveEntityView( public EntityView saveEntityView(
@ApiParam(value = "A JSON object representing the entity view.") @ApiParam(value = "A JSON object representing the entity view.")
@RequestBody EntityView entityView) throws ThingsboardException { @RequestBody EntityView entityView) throws Exception {
entityView.setTenantId(getCurrentUser().getTenantId()); entityView.setTenantId(getCurrentUser().getTenantId());
EntityView existingEntityView = null; EntityView existingEntityView = null;
if (entityView.getId() == null) { if (entityView.getId() == null) {
@ -452,7 +454,8 @@ public class EntityViewController extends BaseController {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
checkEntityViewId(entityViewId, Operation.READ); 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)", @ApiOperation(value = "Unassign entity view from edge (unassignEntityViewFromEdge)",
@ -476,7 +479,8 @@ public class EntityViewController extends BaseController {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
EntityView entityView = checkEntityViewId(entityViewId, Operation.READ); 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')") @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.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.Operation;
import org.thingsboard.server.service.security.permission.Resource; 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.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION; 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); checkEntity(otaPackageInfo.getId(), otaPackageInfo, Resource.OTA_PACKAGE);
return tbOtaPackageService.save(otaPackageInfo, getCurrentUser()); return tbOtaPackageService.save(otaPackageInfo, getCurrentUser());
} }
@ApiOperation(value = "Save OTA Package data (saveOtaPackageData)", @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) @ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES)
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr, @RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@ApiParam(value = "OTA Package data.") @ApiParam(value = "OTA Package data.")
@RequestPart MultipartFile file) throws ThingsboardException { @RequestPart MultipartFile file) throws ThingsboardException, IOException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr); checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo otaPackageInfo = checkOtaPackageInfoId(otaPackageId, Operation.READ); OtaPackageInfo otaPackageInfo = checkOtaPackageInfoId(otaPackageId, Operation.READ);
try { ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase());
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase()); byte[] data = file.getBytes();
byte[] data = file.getBytes(); return tbOtaPackageService.saveOtaPackageData(otaPackageInfo, checksum, checksumAlgorithm,
return tbOtaPackageService.saveOtaPackageData(otaPackageInfo, checksum, checksumAlgorithm, data, file.getOriginalFilename(), file.getContentType(), getCurrentUser());
data, file.getOriginalFilename(), file.getContentType(), getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
} }
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)", @ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
@ -260,7 +256,6 @@ public class OtaPackageController extends BaseController {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo otaPackageInfo = checkOtaPackageInfoId(otaPackageId, Operation.DELETE); OtaPackageInfo otaPackageInfo = checkOtaPackageInfoId(otaPackageId, Operation.DELETE);
tbOtaPackageService.delete(otaPackageInfo, getCurrentUser()); tbOtaPackageService.delete(otaPackageInfo, getCurrentUser());
} }

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

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -37,6 +39,22 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.util.UUID; 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 @RestController
@TbCoreComponent @TbCoreComponent
@RequestMapping("/api") @RequestMapping("/api")
@ -45,82 +63,100 @@ public class QueueController extends BaseController {
private final TbQueueService tbQueueService; 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')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET) @RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody @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, @RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page, @RequestParam int page,
@ApiParam(value = QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch, @RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty, @RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException { @RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("serviceType", serviceType); checkParameter("serviceType", serviceType);
try { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); ServiceType type = ServiceType.valueOf(serviceType);
ServiceType type = ServiceType.valueOf(serviceType); switch (type) {
switch (type) { case TB_RULE_ENGINE:
case TB_RULE_ENGINE: return queueService.findQueuesByTenantId(getTenantId(), pageLink);
return queueService.findQueuesByTenantId(getTenantId(), pageLink); default:
default: return new PageData<>();
return new PageData<>();
}
} catch (Exception e) {
throw handleException(e);
} }
} }
@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')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.GET) @RequestMapping(value = "/queues/{queueId}", method = RequestMethod.GET)
@ResponseBody @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); checkParameter("queueId", queueIdStr);
try { QueueId queueId = new QueueId(UUID.fromString(queueIdStr));
QueueId queueId = new QueueId(UUID.fromString(queueIdStr)); checkQueueId(queueId, Operation.READ);
checkQueueId(queueId, Operation.READ); return checkNotNull(queueService.findQueueById(getTenantId(), queueId));
return checkNotNull(queueService.findQueueById(getTenantId(), queueId)); }
} catch (
Exception e) { @ApiOperation(value = "Get Queue (getQueueByName)",
throw handleException(e); 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')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST) @RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST)
@ResponseBody @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 { @RequestParam String serviceType) throws ThingsboardException {
checkParameter("serviceType", serviceType); 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); ServiceType type = ServiceType.valueOf(serviceType);
switch (type) { switch (type) {
case TB_RULE_ENGINE: case TB_RULE_ENGINE:
queue.setTenantId(getTenantId()); queue.setTenantId(getTenantId());
Queue savedQueue = tbQueueService.saveQueue(queue); Queue savedQueue = tbQueueService.saveQueue(queue);
checkNotNull(savedQueue); checkNotNull(savedQueue);
return savedQueue; return savedQueue;
default: default:
return null; return null;
}
} catch (Exception e) {
throw handleException(e);
} }
} }
@ApiOperation(value = "Delete Queue (deleteQueue)", notes = "Deletes the Queue. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.DELETE) @RequestMapping(value = "/queues/{queueId}", method = RequestMethod.DELETE)
@ResponseBody @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); checkParameter("queueId", queueIdStr);
try { QueueId queueId = new QueueId(toUUID(queueIdStr));
QueueId queueId = new QueueId(toUUID(queueIdStr)); checkQueueId(queueId, Operation.DELETE);
checkQueueId(queueId, Operation.DELETE); tbQueueService.deleteQueue(getTenantId(), queueId);
tbQueueService.deleteQueue(getTenantId(), queueId);
} catch (Exception e) {
throw handleException(e);
}
} }
} }

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.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; 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. " + "The newly created Rule Chain Id will be present in the response. " +
"Specify existing Rule Chain id to update the rule chain. " + "Specify existing Rule Chain id to update the rule chain. " +
"Referencing non-existing rule chain Id will cause 'Not Found' error." + "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')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST) @RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public RuleChain saveRuleChain( public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the rule chain.") @ApiParam(value = "A JSON value representing the rule chain.")
@RequestBody RuleChain ruleChain) throws ThingsboardException { @RequestBody RuleChain ruleChain) throws Exception {
ruleChain.setTenantId(getCurrentUser().getTenantId()); ruleChain.setTenantId(getCurrentUser().getTenantId());
checkEntity(ruleChain.getId(), ruleChain, Resource.RULE_CHAIN); checkEntity(ruleChain.getId(), ruleChain, Resource.RULE_CHAIN);
return tbRuleChainService.save(ruleChain, getCurrentUser()); return tbRuleChainService.save(ruleChain, getCurrentUser());
} }
@ApiOperation(value = "Create Default Rule Chain", @ApiOperation(value = "Create Default Rule Chain",
notes = "Create rule chain from template, based on the specified name in the request. " + notes = "Create rule chain from template, based on the specified name in the request. " +
@ -247,12 +249,11 @@ public class RuleChainController extends BaseController {
@ResponseBody @ResponseBody
public RuleChain saveRuleChain( public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the request.") @ApiParam(value = "A JSON value representing the request.")
@RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException { @RequestBody DefaultRuleChainCreateRequest request) throws Exception {
checkNotNull(request); checkNotNull(request);
checkParameter(request.getName(), "name"); checkParameter(request.getName(), "name");
return tbRuleChainService.saveDefaultByName(getTenantId(), request, getCurrentUser()); return tbRuleChainService.saveDefaultByName(getTenantId(), request, getCurrentUser());
} }
@ApiOperation(value = "Set Root Rule Chain (setRootRuleChain)", @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) 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); checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
return tbRuleChainService.setRootRuleChain(getTenantId(),ruleChain, getCurrentUser()); return tbRuleChainService.setRootRuleChain(getTenantId(), ruleChain, getCurrentUser());
} }
@ApiOperation(value = "Update Rule Chain Metadata", @ApiOperation(value = "Update Rule Chain Metadata",
@ -279,7 +279,7 @@ public class RuleChainController extends BaseController {
@RequestBody RuleChainMetaData ruleChainMetaData, @RequestBody RuleChainMetaData ruleChainMetaData,
@ApiParam(value = "Update related rule nodes.") @ApiParam(value = "Update related rule nodes.")
@RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated @RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated
) throws ThingsboardException { ) throws Exception {
TenantId tenantId = getTenantId(); TenantId tenantId = getTenantId();
if (debugPerTenantEnabled) { if (debugPerTenantEnabled) {
ConcurrentMap<TenantId, DebugTbRateLimits> debugPerTenantLimits = actorContext.getDebugPerTenantLimits(); ConcurrentMap<TenantId, DebugTbRateLimits> debugPerTenantLimits = actorContext.getDebugPerTenantLimits();
@ -290,9 +290,8 @@ public class RuleChainController extends BaseController {
} }
RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE); RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
return tbRuleChainService.saveRuleChainMetaData(tenantId, ruleChain, ruleChainMetaData, updateRelated, return tbRuleChainService.saveRuleChainMetaData(tenantId, ruleChain, ruleChainMetaData, updateRelated, getCurrentUser());
getCurrentUser()); }
}
@ApiOperation(value = "Get Rule Chains (getRuleChains)", @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) 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) @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId); checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.DELETE); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.DELETE);
tbRuleChainService.delete(ruleChain, getCurrentUser()); tbRuleChainService.delete(ruleChain, getCurrentUser());
} }
@ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)", @ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)",
notes = "Gets the input message from the debug events for specified Rule Chain Id. " + 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); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.assignRuleChainToEdge(getTenantId(), ruleChain, edge, getCurrentUser()); return tbRuleChainService.assignRuleChainToEdge(getTenantId(), ruleChain, edge, getCurrentUser());
} }
@ApiOperation(value = "Unassign rule chain from edge (unassignRuleChainFromEdge)", @ApiOperation(value = "Unassign rule chain from edge (unassignRuleChainFromEdge)",
notes = "Clears assignment of the rule chain to the edge. " + 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); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.unassignRuleChainFromEdge(getTenantId(), ruleChain, edge, getCurrentUser()); return tbRuleChainService.unassignRuleChainFromEdge(getTenantId(), ruleChain, edge, getCurrentUser());
} }
@ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)", @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) 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)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
return tbRuleChainService.setAutoAssignToEdgeRuleChain(getTenantId(), ruleChain, getCurrentUser()); return tbRuleChainService.setAutoAssignToEdgeRuleChain(getTenantId(), ruleChain, getCurrentUser());
} }
@ApiOperation(value = "Unset Auto Assign To Edge Rule Chain (unsetAutoAssignToEdgeRuleChain)", @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. " + 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); checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
return tbRuleChainService.unsetAutoAssignToEdgeRuleChain(getTenantId(), ruleChain, getCurrentUser()); return tbRuleChainService.unsetAutoAssignToEdgeRuleChain(getTenantId(), ruleChain, getCurrentUser());
} }
// TODO: @voba refactor this - add new config to edge rule chain to set it as auto-assign // 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)", @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 @RequiredArgsConstructor
public class TbResourceController extends BaseController { public class TbResourceController extends BaseController {
private final TbResourceService tbResourceService; private final TbResourceService tbResourceService;
public static final String RESOURCE_ID = "resourceId"; 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. " + "The newly created Resource id will be present in the response. " +
"Specify existing Resource id to update the Resource. " + "Specify existing Resource id to update the Resource. " +
"Referencing non-existing Resource Id will cause 'Not Found' error. " + "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", produces = "application/json",
consumes = "application/json") consumes = "application/json")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource", method = RequestMethod.POST) @RequestMapping(value = "/resource", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public TbResource saveResource(@ApiParam(value = "A JSON value representing the Resource.") public TbResource saveResource(@ApiParam(value = "A JSON value representing the Resource.")
@RequestBody TbResource resource) throws ThingsboardException { @RequestBody TbResource resource) throws Exception {
resource.setTenantId(getTenantId()); resource.setTenantId(getTenantId());
checkEntity(resource.getId(), resource, Resource.TB_RESOURCE); checkEntity(resource.getId(), resource, Resource.TB_RESOURCE);
return tbResourceService.save(resource, getCurrentUser()); 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) { private void logTimeseriesDeleted(SecurityUser user, EntityId entityId, List<String> keys, long startTs, long endTs, Throwable e) {
try { notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.TIMESERIES_DELETED, user,
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_DELETED, toException(e), toException(e), keys, startTs, endTs);
keys, startTs, endTs);
} catch (ThingsboardException te) {
log.warn("Failed to log timeseries delete", te);
}
} }
private void logTelemetryUpdated(SecurityUser user, EntityId entityId, List<TsKvEntry> telemetry, Throwable e) { private void logTelemetryUpdated(SecurityUser user, EntityId entityId, List<TsKvEntry> telemetry, Throwable e) {
try { notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.TIMESERIES_UPDATED, user,
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_UPDATED, toException(e), telemetry); toException(e), telemetry);
} catch (ThingsboardException te) {
log.warn("Failed to log telemetry update");
}
} }
private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) { private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
try { notificationEntityService.logEntityAction(user.getTenantId(), (UUIDBased & EntityId) entityId,
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_DELETED, toException(e), ActionType.ATTRIBUTES_DELETED, user, toException(e), scope, keys);
scope, keys);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes delete", te);
}
} }
private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) { private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) {
try { notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.ATTRIBUTES_UPDATED, user,
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e), toException(e), scope, attributes);
scope, attributes);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes update", te);
}
} }
private void logAttributesRead(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) { private void logAttributesRead(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
try { notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.ATTRIBUTES_READ, user,
logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_READ, toException(e), toException(e), scope, keys);
scope, keys);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes read", te);
}
} }
private ListenableFuture<List<AttributeKvEntry>> mergeAllAttributesFutures(List<ListenableFuture<List<AttributeKvEntry>>> futures) { 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. " + "The newly created Tenant Id will be present in the response. " +
"Specify existing Tenant Id id to update the Tenant. " + "Specify existing Tenant Id id to update the Tenant. " +
"Referencing non-existing Tenant Id will cause 'Not Found' error." + "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) SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')") @PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant", method = RequestMethod.POST) @RequestMapping(value = "/tenant", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Tenant saveTenant(@ApiParam(value = "A JSON value representing the tenant.") 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); checkEntity(tenant.getId(), tenant, Resource.TENANT);
return tbTenantService.save(tenant); return tbTenantService.save(tenant);
} }
@ -131,7 +132,7 @@ public class TenantController extends BaseController {
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE) @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK) @ResponseStatus(value = HttpStatus.OK)
public void deleteTenant(@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION) 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); checkParameter(TENANT_ID, strTenantId);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId)); TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
Tenant tenant = checkTenantId(tenantId, Operation.DELETE); 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.EntityInfo;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.ThingsboardException; 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.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; 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.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.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
@ -130,7 +128,6 @@ public class TenantProfileController extends BaseController {
"{\n" + "{\n" +
" \"name\": \"Default\",\n" + " \"name\": \"Default\",\n" +
" \"description\": \"Default tenant profile\",\n" + " \"description\": \"Default tenant profile\",\n" +
" \"isolatedTbCore\": false,\n" +
" \"isolatedTbRuleEngine\": false,\n" + " \"isolatedTbRuleEngine\": false,\n" +
" \"profileData\": {\n" + " \"profileData\": {\n" +
" \"configuration\": {\n" + " \"configuration\": {\n" +
@ -167,30 +164,23 @@ public class TenantProfileController extends BaseController {
" \"default\": true\n" + " \"default\": true\n" +
"}" + "}" +
MARKDOWN_CODE_BLOCK_END + MARKDOWN_CODE_BLOCK_END +
"Remove 'id', from the request body example (below) to create new Tenant Profile entity." +
SYSTEM_AUTHORITY_PARAGRAPH) SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')") @PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile", method = RequestMethod.POST) @RequestMapping(value = "/tenantProfile", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public TenantProfile saveTenantProfile( public TenantProfile saveTenantProfile(@ApiParam(value = "A JSON value representing the tenant profile.")
@ApiParam(value = "A JSON value representing the tenant profile.") @RequestBody TenantProfile tenantProfile) throws ThingsboardException {
@RequestBody TenantProfile tenantProfile) throws ThingsboardException {
try { try {
boolean newTenantProfile = tenantProfile.getId() == null;
TenantProfile oldProfile; TenantProfile oldProfile;
if (newTenantProfile) { if (tenantProfile.getId() == null) {
accessControlService accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
oldProfile = null; oldProfile = null;
} else { } else {
oldProfile = checkTenantProfileId(tenantProfile.getId(), Operation.WRITE); oldProfile = checkTenantProfileId(tenantProfile.getId(), Operation.WRITE);
} }
tenantProfile = checkNotNull(tbTenantProfileService.saveTenantProfile(getTenantId(), tenantProfile, oldProfile)); return tbTenantProfileService.save(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;
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }
@ -201,15 +191,13 @@ public class TenantProfileController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')") @PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.DELETE) @RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK) @ResponseStatus(value = HttpStatus.OK)
public void deleteTenantProfile( public void deleteTenantProfile(@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION) @PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try { try {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE); TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE);
tenantProfileService.deleteTenantProfile(getTenantId(), tenantProfileId); tbTenantProfileService.delete(getTenantId(), profile);
tbClusterService.onTenantProfileDelete(profile, null);
} catch (Exception e) { } catch (Exception e) {
throw handleException(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") @RequestMapping("/api/2fa")
@TbCoreComponent @TbCoreComponent
@RequiredArgsConstructor @RequiredArgsConstructor
public class TwoFaConfigController extends BaseController { public class TwoFactorAuthConfigController extends BaseController {
private final TwoFaConfigManager twoFaConfigManager; private final TwoFaConfigManager twoFaConfigManager;
private final TwoFactorAuthService twoFactorAuthService; 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)", @ApiOperation(value = "Get User (getUserById)",
notes = "Fetch the User object based on the provided User Id. " + 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 '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 '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 'CUSTOMER_USER', the server checks that the requested user is owned by the same customer.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET) @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -176,7 +176,9 @@ public class UserController extends BaseController {
"The newly created User Id will be present in the response. " + "The newly created User Id will be present in the response. " +
"Specify existing User Id to update the device. " + "Specify existing User Id to update the device. " +
"Referencing non-existing User Id will cause 'Not Found' error." + "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')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user", method = RequestMethod.POST) @RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody @ResponseBody
@ -190,7 +192,7 @@ public class UserController extends BaseController {
} }
checkEntity(user.getId(), user, Resource.USER); checkEntity(user.getId(), user, Resource.USER);
return tbUserService.save(getTenantId(), getCurrentUser().getCustomerId(), user, sendActivationMail, request, getCurrentUser()); return tbUserService.save(getTenantId(), getCurrentUser().getCustomerId(), user, sendActivationMail, request, getCurrentUser());
} }
@ApiOperation(value = "Send or re-send the activation email", @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) 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.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetTypeInfo; 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.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
@ -52,7 +53,7 @@ import static org.thingsboard.server.controller.ControllerConstants.WIDGET_TYPE_
@RestController @RestController
@TbCoreComponent @TbCoreComponent
@RequestMapping("/api") @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_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. " + 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. " + "Specify existing Widget Type id to update the Widget Type. " +
"Referencing non-existing Widget Type Id will cause 'Not Found' error." + "Referencing non-existing Widget Type Id will cause 'Not Found' error." +
"\n\nWidget Type alias is unique in the scope of Widget Bundle. " + "\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." "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) "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')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/widgetType", method = RequestMethod.POST) @RequestMapping(value = "/widgetType", method = RequestMethod.POST)
@ResponseBody @ResponseBody
@ -93,15 +95,23 @@ public class WidgetTypeController extends BaseController {
@ApiParam(value = "A JSON value representing the Widget Type Details.", required = true) @ApiParam(value = "A JSON value representing the Widget Type Details.", required = true)
@RequestBody WidgetTypeDetails widgetTypeDetails) throws ThingsboardException { @RequestBody WidgetTypeDetails widgetTypeDetails) throws ThingsboardException {
try { try {
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
widgetTypeDetails.setTenantId(TenantId.SYS_TENANT_ID); widgetTypeDetails.setTenantId(TenantId.SYS_TENANT_ID);
} else { } else {
widgetTypeDetails.setTenantId(getCurrentUser().getTenantId()); widgetTypeDetails.setTenantId(currentUser.getTenantId());
} }
checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE); checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE);
WidgetTypeDetails savedWidgetTypeDetails = widgetTypeService.saveWidgetType(widgetTypeDetails); 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(), sendEntityNotificationMsg(getTenantId(), savedWidgetTypeDetails.getId(),
widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
@ -121,9 +131,17 @@ public class WidgetTypeController extends BaseController {
@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { @PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException {
checkParameter("widgetTypeId", strWidgetTypeId); checkParameter("widgetTypeId", strWidgetTypeId);
try { try {
var currentUser = getCurrentUser();
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
checkWidgetTypeId(widgetTypeId, Operation.DELETE); WidgetTypeDetails wtd = checkWidgetTypeId(widgetTypeId, Operation.DELETE);
widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId); 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); 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.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.Operation;
import org.thingsboard.server.service.security.permission.Resource; 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. " + "Specify existing Widget Bundle id to update the Widget Bundle. " +
"Referencing non-existing Widget Bundle Id will cause 'Not Found' error." + "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." +
"\n\nWidget Bundle alias is unique in the scope of tenant. " + "\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." "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) "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')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST) @RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public WidgetsBundle saveWidgetsBundle( public WidgetsBundle saveWidgetsBundle(
@ApiParam(value = "A JSON value representing the Widget Bundle.", required = true) @ApiParam(value = "A JSON value representing the Widget Bundle.", required = true)
@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { @RequestBody WidgetsBundle widgetsBundle) throws Exception {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID); widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID);
} else { } else {
widgetsBundle.setTenantId(getCurrentUser().getTenantId()); 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)", @ApiOperation(value = "Delete widgets bundle (deleteWidgetsBundle)",
@ -120,7 +121,7 @@ public class WidgetsBundleController extends BaseController {
checkParameter("widgetsBundleId", strWidgetsBundleId); checkParameter("widgetsBundleId", strWidgetsBundleId);
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
WidgetsBundle widgetsBundle = checkWidgetsBundleId(widgetsBundleId, Operation.DELETE); WidgetsBundle widgetsBundle = checkWidgetsBundleId(widgetsBundleId, Operation.DELETE);
tbWidgetsBundleService.delete(widgetsBundle, getCurrentUser()); tbWidgetsBundleService.delete(widgetsBundle);
} }
@ApiOperation(value = "Get Widget Bundles (getWidgetsBundles)", @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; package org.thingsboard.server.controller.plugin;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.BeanCreationNotAllowedException; import org.springframework.beans.factory.BeanCreationNotAllowedException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage; import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage; 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.data.id.UserId;
import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.config.WebSocketConfiguration; import org.thingsboard.server.config.WebSocketConfiguration;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal; 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.SessionEvent;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketMsgEndpoint; import org.thingsboard.server.service.telemetry.TelemetryWebSocketMsgEndpoint;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; import org.thingsboard.server.service.telemetry.TelemetryWebSocketService;
@ -72,22 +72,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
@Autowired @Autowired
private TelemetryWebSocketService webSocketService; private TelemetryWebSocketService webSocketService;
@Autowired
private TbTenantProfileCache tenantProfileCache;
@Value("${server.ws.send_timeout:5000}") @Value("${server.ws.send_timeout:5000}")
private long sendTimeout; 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}") @Value("${server.ws.ping_timeout:30000}")
private long pingTimeout; private long pingTimeout;
@ -144,10 +133,13 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
String internalSessionId = session.getId(); String internalSessionId = session.getId();
TelemetryWebSocketSessionRef sessionRef = toRef(session); TelemetryWebSocketSessionRef sessionRef = toRef(session);
String externalSessionId = sessionRef.getSessionId(); String externalSessionId = sessionRef.getSessionId();
if (!checkLimits(session, sessionRef)) { if (!checkLimits(session, sessionRef)) {
return; 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); externalSessionMap.put(externalSessionId, internalSessionId);
processInWebSocketService(sessionRef, SessionEvent.onEstablished()); processInWebSocketService(sessionRef, SessionEvent.onEstablished());
@ -323,8 +315,9 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
if (internalId != null) { if (internalId != null) {
SessionMetaData sessionMd = internalSessionMap.get(internalId); SessionMetaData sessionMd = internalSessionMap.get(internalId);
if (sessionMd != null) { if (sessionMd != null) {
if (!StringUtils.isEmpty(perSessionUpdatesConfiguration)) { var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
TbRateLimits rateLimits = perSessionUpdateLimits.computeIfAbsent(sessionRef.getSessionId(), sid -> new TbRateLimits(perSessionUpdatesConfiguration)); if (StringUtils.isNotEmpty(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit())) {
TbRateLimits rateLimits = perSessionUpdateLimits.computeIfAbsent(sessionRef.getSessionId(), sid -> new TbRateLimits(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit()));
if (!rateLimits.tryConsume()) { if (!rateLimits.tryConsume()) {
if (blacklistedSessions.putIfAbsent(externalId, sessionRef) == null) { if (blacklistedSessions.putIfAbsent(externalId, sessionRef) == null) {
log.info("[{}][{}][{}] Failed to process session update. Max session updates limit reached" 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); log.debug("[{}][{}][{}] Session is no longer blacklisted.", sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), externalId);
blacklistedSessions.remove(externalId); blacklistedSessions.remove(externalId);
} }
} else {
perSessionUpdateLimits.remove(sessionRef.getSessionId());
} }
sessionMd.sendMsg(msg); sessionMd.sendMsg(msg);
} else { } else {
@ -380,11 +375,17 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
} }
private boolean checkLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) throws Exception { 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(); String sessionId = session.getId();
if (maxSessionsPerTenant > 0) { if (tenantProfileConfiguration.getMaxWsSessionsPerTenant() > 0) {
Set<String> tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet()); Set<String> tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet());
synchronized (tenantSessions) { synchronized (tenantSessions) {
if (tenantSessions.size() < maxSessionsPerTenant) { if (tenantSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerTenant()) {
tenantSessions.add(sessionId); tenantSessions.add(sessionId);
} else { } else {
log.info("[{}][{}][{}] Failed to start session. Max tenant sessions limit reached" 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 (sessionRef.getSecurityCtx().isCustomerUser()) {
if (maxSessionsPerCustomer > 0) { if (tenantProfileConfiguration.getMaxWsSessionsPerCustomer() > 0) {
Set<String> customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet()); Set<String> customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet());
synchronized (customerSessions) { synchronized (customerSessions) {
if (customerSessions.size() < maxSessionsPerCustomer) { if (customerSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerCustomer()) {
customerSessions.add(sessionId); customerSessions.add(sessionId);
} else { } else {
log.info("[{}][{}][{}] Failed to start session. Max customer sessions limit reached" 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()); Set<String> regularUserSessions = regularUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (regularUserSessions) { synchronized (regularUserSessions) {
if (regularUserSessions.size() < maxSessionsPerRegularUser) { if (regularUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerRegularUser()) {
regularUserSessions.add(sessionId); regularUserSessions.add(sessionId);
} else { } else {
log.info("[{}][{}][{}] Failed to start session. Max regular user sessions limit reached" 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()); Set<String> publicUserSessions = publicUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (publicUserSessions) { synchronized (publicUserSessions) {
if (publicUserSessions.size() < maxSessionsPerPublicUser) { if (publicUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerPublicUser()) {
publicUserSessions.add(sessionId); publicUserSessions.add(sessionId);
} else { } else {
log.info("[{}][{}][{}] Failed to start session. Max public user sessions limit reached" 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) { private void cleanupLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) {
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
String sessionId = session.getId(); String sessionId = session.getId();
perSessionUpdateLimits.remove(sessionRef.getSessionId()); perSessionUpdateLimits.remove(sessionRef.getSessionId());
blacklistedSessions.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()); Set<String> tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet());
synchronized (tenantSessions) { synchronized (tenantSessions) {
tenantSessions.remove(sessionId); tenantSessions.remove(sessionId);
} }
} }
if (sessionRef.getSecurityCtx().isCustomerUser()) { if (sessionRef.getSecurityCtx().isCustomerUser()) {
if (maxSessionsPerCustomer > 0) { if (tenantProfileConfiguration.getMaxWsSessionsPerCustomer() > 0) {
Set<String> customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet()); Set<String> customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet());
synchronized (customerSessions) { synchronized (customerSessions) {
customerSessions.remove(sessionId); 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()); Set<String> regularUserSessions = regularUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (regularUserSessions) { synchronized (regularUserSessions) {
regularUserSessions.remove(sessionId); 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()); Set<String> publicUserSessions = publicUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet());
synchronized (publicUserSessions) { synchronized (publicUserSessions) {
publicUserSessions.remove(sessionId); 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); 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() { public String getResetToken() {
return resetToken; 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); 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() { public Integer getStatus() {
return status.value(); 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() { public String getMessage() {
return message; return message;
} }
@ -69,12 +69,12 @@ public class ThingsboardErrorResponse {
"\n\n* `34` - Too many updates (Too many updates over Websocket session)" + "\n\n* `34` - Too many updates (Too many updates over Websocket session)" +
"\n\n* `40` - Subscription violation (HTTP: 403 - Forbidden)", "\n\n* `40` - Subscription violation (HTTP: 403 - Forbidden)",
example = "10", dataType = "integer", example = "10", dataType = "integer",
readOnly = true) accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public ThingsboardErrorCode getErrorCode() { public ThingsboardErrorCode getErrorCode() {
return errorCode; return errorCode;
} }
@ApiModelProperty(position = 4, value = "Timestamp", readOnly = true) @ApiModelProperty(position = 4, value = "Timestamp", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Date getTimestamp() { public Date getTimestamp() {
return timestamp; 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 lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; 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.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; 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.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.cluster.TbClusterService;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@TbCoreComponent
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @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) { ActionType actionType, Exception e, Object... additionalInfo) {
if (customerId == null || customerId.isNullUid()) { if (customerId == null || customerId.isNullUid()) {
customerId = user.getCustomerId(); customerId = user.getCustomerId();
@ -223,6 +222,9 @@ public class EntityActionService {
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); 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) { private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) {
T result = null; T result = null;
@ -267,4 +269,5 @@ public class EntityActionService {
entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString()); 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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; import org.thingsboard.server.common.data.id.TenantId;
public interface TbTenantProfileService { public interface RateLimitService {
TenantProfile saveTenantProfile(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile);
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.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.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 org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Map; 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); configurationDescriptor.set("nodeDefinition", node);
scannedComponent.setConfigurationDescriptor(configurationDescriptor); scannedComponent.setConfigurationDescriptor(configurationDescriptor);
scannedComponent.setClazz(clazzName); scannedComponent.setClazz(clazzName);
log.info("Processing scanned component: {}", scannedComponent); log.debug("Processing scanned component: {}", scannedComponent);
} catch (Exception e) { } catch (Exception e) {
log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
ComponentDescriptor persistedComponent = componentDescriptorService.findByClazz(TenantId.SYS_TENANT_ID, clazzName); ComponentDescriptor persistedComponent = componentDescriptorService.findByClazz(TenantId.SYS_TENANT_ID, clazzName);
if (persistedComponent == null) { if (persistedComponent == null) {
log.info("Persisting new component: {}", scannedComponent); log.debug("Persisting new component: {}", scannedComponent);
scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent); scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent);
} else if (scannedComponent.equals(persistedComponent)) { } else if (scannedComponent.equals(persistedComponent)) {
log.info("Component is already persisted: {}", persistedComponent); log.debug("Component is already persisted: {}", persistedComponent);
scannedComponent = persistedComponent; scannedComponent = persistedComponent;
} else { } 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()); componentDescriptorService.deleteByClazz(TenantId.SYS_TENANT_ID, persistedComponent.getClazz());
scannedComponent.setId(persistedComponent.getId()); scannedComponent.setId(persistedComponent.getId());
scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent); scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent);
@ -224,7 +224,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
@Override @Override
public void discoverComponents() { public void discoverComponents() {
registerRuleNodeComponents(); registerRuleNodeComponents();
log.info("Found following definitions: {}", components.values()); log.debug("Found following definitions: {}", components.values());
} }
@Override @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.cache.CacheManager;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Customer; 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 org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.common.data.CacheConstants.CLAIM_DEVICES_CACHE; import static org.thingsboard.server.common.data.CacheConstants.CLAIM_DEVICES_CACHE;
@ -122,55 +121,57 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
}, MoreExecutors.directExecutor()); }, 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()); List<Object> key = constructCacheKey(device.getId());
ClaimData claimDataFromCache = cache.get(key, ClaimData.class); ClaimData claimDataFromCache = cache.get(key, ClaimData.class);
if (claimDataFromCache != null) { if (claimDataFromCache != null) {
return new ClaimDataInfo(true, key, claimDataFromCache); return Futures.immediateFuture(new ClaimDataInfo(true, key, claimDataFromCache));
} else { } else {
Optional<AttributeKvEntry> claimDataAttr = attributesService.find(device.getTenantId(), device.getId(), ListenableFuture<Optional<AttributeKvEntry>> claimDataAttrFuture = attributesService.find(device.getTenantId(), device.getId(),
DataConstants.SERVER_SCOPE, CLAIM_DATA_ATTRIBUTE_NAME).get(); DataConstants.SERVER_SCOPE, CLAIM_DATA_ATTRIBUTE_NAME);
if (claimDataAttr.isPresent()) {
try { return Futures.transform(claimDataAttrFuture, claimDataAttr -> {
ClaimData claimDataFromAttribute = mapper.readValue(claimDataAttr.get().getValueAsString(), ClaimData.class); if (claimDataAttr.isPresent()) {
ClaimData claimDataFromAttribute = JacksonUtil.fromString(claimDataAttr.get().getValueAsString(), ClaimData.class);
return new ClaimDataInfo(false, key, claimDataFromAttribute); 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 @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); Cache cache = cacheManager.getCache(CLAIM_DEVICES_CACHE);
ClaimDataInfo claimData = getClaimData(cache, device); ListenableFuture<ClaimDataInfo> claimDataFuture = getClaimData(cache, device);
if (claimData != null) {
long currTs = System.currentTimeMillis(); return Futures.transformAsync(claimDataFuture, claimData -> {
if (currTs > claimData.getData().getExpirationTime() || !secretKeyIsEmptyOrEqual(secretKey, claimData.getData().getSecretKey())) { if (claimData != null) {
log.warn("The claiming timeout occurred or wrong 'secretKey' provided for the device [{}]", device.getName()); long currTs = System.currentTimeMillis();
if (claimData.isFromCache()) { if (currTs > claimData.getData().getExpirationTime() || !secretKeyIsEmptyOrEqual(secretKey, claimData.getData().getSecretKey())) {
cache.evict(claimData.getKey()); 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 { } else {
log.warn("Failed to find the device's claiming message![{}]", device.getName());
if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
device.setCustomerId(customerId); return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
Device savedDevice = deviceService.saveDevice(device); } else {
clusterService.onDeviceUpdated(savedDevice, device); return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.CLAIMED));
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());
} }
} else { }, MoreExecutors.directExecutor());
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));
}
}
} }
private boolean secretKeyIsEmptyOrEqual(String secretKeyA, String secretKeyB) { 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.device.DeviceService;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.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 org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Collection; import java.util.Collection;
@ -121,7 +121,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
} }
entity.setDeviceProfileId(deviceProfile.getId()); entity.setDeviceProfileId(deviceProfile.getId());
return tbDeviceService.saveDeviceWithCredentials(user.getTenantId(), entity, deviceCredentials, user); return tbDeviceService.saveDeviceWithCredentials(entity, deviceCredentials, user);
} }
@Override @Override
@ -176,7 +176,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode(); ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode();
Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE, 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) .map(fields::get)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.forEach(securityMode -> { .forEach(securityMode -> {
@ -233,7 +233,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration();
transportConfiguration.setBootstrap(Collections.emptyList()); 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())); transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap()));
DeviceProfileData deviceProfileData = new DeviceProfileData(); 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 ENTITY_VIEW:
case DASHBOARD: case DASHBOARD:
case RULE_CHAIN: case RULE_CHAIN:
case OTA_PACKAGE:
future = entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg); future = entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break; break;
case CUSTOMER: case CUSTOMER:
@ -144,6 +145,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
break; break;
case WIDGETS_BUNDLE: case WIDGETS_BUNDLE:
case WIDGET_TYPE: case WIDGET_TYPE:
case QUEUE:
future = entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); future = entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
break; break;
case ALARM: 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.edge.EdgeService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.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 org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Map; 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.device.DeviceProfileService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; 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.rule.RuleChainService;
import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.user.UserService; 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.DeviceProfileEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.EntityEdgeProcessor; 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.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.RelationEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.RuleChainEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.RuleChainEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.TelemetryEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.TelemetryEdgeProcessor;
@ -93,6 +97,12 @@ public class EdgeContextComponent {
@Autowired @Autowired
private EdgeRequestsService edgeRequestsService; private EdgeRequestsService edgeRequestsService;
@Autowired
private OtaPackageService otaPackageService;
@Autowired
private QueueService queueService;
@Autowired @Autowired
private AlarmEdgeProcessor alarmProcessor; private AlarmEdgeProcessor alarmProcessor;
@ -138,6 +148,12 @@ public class EdgeContextComponent {
@Autowired @Autowired
private AdminSettingsEdgeProcessor adminSettingsProcessor; private AdminSettingsEdgeProcessor adminSettingsProcessor;
@Autowired
private OtaPackageEdgeProcessor otaPackageEdgeProcessor;
@Autowired
private QueueEdgeProcessor queueEdgeProcessor;
@Autowired @Autowired
private EdgeEventStorageSettings edgeEventStorageSettings; 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); return ctx.getWidgetTypeProcessor().processWidgetTypeToEdge(edgeEvent, msgType, action);
case ADMIN_SETTINGS: case ADMIN_SETTINGS:
return ctx.getAdminSettingsProcessor().processAdminSettingsToEdge(edgeEvent); 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: default:
log.warn("Unsupported edge event type [{}]", edgeEvent); log.warn("Unsupported edge event type [{}]", edgeEvent);
return null; 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.DashboardsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetcher; 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.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.RuleChainsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.SystemWidgetsBundlesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.SystemWidgetsBundlesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.TenantAdminUsersEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.TenantAdminUsersEdgeEventFetcher;
@ -41,6 +43,7 @@ public class EdgeSyncCursor {
int currentIdx = 0; int currentIdx = 0;
public EdgeSyncCursor(EdgeContextComponent ctx, Edge edge) { public EdgeSyncCursor(EdgeContextComponent ctx, Edge edge) {
fetchers.add(new QueuesEdgeEventFetcher(ctx.getQueueService()));
fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService())); fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService()));
fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), ctx.getFreemarkerConfig())); fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), ctx.getFreemarkerConfig()));
fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService())); fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService()));
@ -53,6 +56,7 @@ public class EdgeSyncCursor {
fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
fetchers.add(new OtaPackagesEdgeEventFetcher(ctx.getOtaPackageService()));
} }
public boolean hasNext() { 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.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.DeviceProfileId; 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.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -48,9 +48,9 @@ public class DeviceProfileMsgConstructor {
// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits()) // builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits()); // .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());
// } // }
// if (deviceProfile.getDefaultQueueName() != null) { if (deviceProfile.getDefaultQueueName() != null) {
// builder.setDefaultQueueName(deviceProfile.getDefaultQueueName()); builder.setDefaultQueueName(deviceProfile.getDefaultQueueName());
// } }
if (deviceProfile.getDescription() != null) { if (deviceProfile.getDescription() != null) {
builder.setDescription(deviceProfile.getDescription()); 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; 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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil; 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.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.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; 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.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.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; 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.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadataConstructor;
import java.util.ArrayList; import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadataConstructorFactory;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
@Component @Component
@Slf4j @Slf4j
@TbCoreComponent @TbCoreComponent
public class RuleChainMsgConstructor { 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) { public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder() RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
@ -69,231 +51,13 @@ public class RuleChainMsgConstructor {
return builder.build(); return builder.build();
} }
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
UpdateMsgType msgType,
RuleChainMetaData ruleChainMetaData, RuleChainMetaData ruleChainMetaData,
EdgeVersion edgeVersion) { EdgeVersion edgeVersion) {
try { RuleChainMetadataConstructor ruleChainMetadataConstructor
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder(); = RuleChainMetadataConstructorFactory.getByEdgeVersion(edgeVersion);
switch (edgeVersion) { return ruleChainMetadataConstructor.constructRuleChainMetadataUpdatedMsg(tenantId, msgType, ruleChainMetaData);
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();
} }
public RuleChainUpdateMsg constructRuleChainDeleteMsg(RuleChainId ruleChainId) { public RuleChainUpdateMsg constructRuleChainDeleteMsg(RuleChainId ruleChainId) {
@ -302,5 +66,4 @@ public class RuleChainMsgConstructor {
.setIdMSB(ruleChainId.getId().getMostSignificantBits()) .setIdMSB(ruleChainId.getId().getMostSignificantBits())
.setIdLSB(ruleChainId.getId().getLeastSignificantBits()).build(); .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, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings))); 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, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings))); 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, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates))); 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, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates))); 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(); AdminSettings tenantMailSettings = new AdminSettings();
tenantMailSettings.setTenantId(tenantId);
jsonValue.put("useSystemMailSettings", true); jsonValue.put("useSystemMailSettings", true);
tenantMailSettings.setJsonValue(jsonValue); tenantMailSettings.setJsonValue(jsonValue);
tenantMailSettings.setKey(key); 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 @Override
protected PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink) { 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 com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils; 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.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService; 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.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator; 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.user.UserService;
import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService; 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.AdminSettingsMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AlarmMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.AlarmMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AssetMsgConstructor; 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.DeviceProfileMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityDataMsgConstructor; 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.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.RelationMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.RuleChainMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.UserMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.UserMsgConstructor;
@ -101,6 +109,9 @@ public abstract class BaseEdgeProcessor {
@Autowired @Autowired
protected EntityViewService entityViewService; protected EntityViewService entityViewService;
@Autowired
protected TenantService tenantService;
@Autowired @Autowired
protected EdgeService edgeService; protected EdgeService edgeService;
@ -137,6 +148,19 @@ public abstract class BaseEdgeProcessor {
@Autowired @Autowired
protected WidgetTypeService widgetTypeService; protected WidgetTypeService widgetTypeService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected QueueService queueService;
@Autowired
protected PartitionService partitionService;
@Autowired
@Lazy
protected TbQueueProducerProvider producerProvider;
@Autowired @Autowired
protected DataValidator<Device> deviceValidator; protected DataValidator<Device> deviceValidator;
@ -182,6 +206,12 @@ public abstract class BaseEdgeProcessor {
@Autowired @Autowired
protected AdminSettingsMsgConstructor adminSettingsMsgConstructor; protected AdminSettingsMsgConstructor adminSettingsMsgConstructor;
@Autowired
protected OtaPackageMsgConstructor otaPackageMsgConstructor;
@Autowired
protected QueueMsgConstructor queueMsgConstructor;
@Autowired @Autowired
protected DbCallbackExecutorService dbCallbackExecutorService; protected DbCallbackExecutorService dbCallbackExecutorService;
@ -212,6 +242,24 @@ public abstract class BaseEdgeProcessor {
} }
protected ListenableFuture<Void> processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) { 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); PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Edge> pageData; PageData<Edge> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>(); List<ListenableFuture<Void>> futures = new ArrayList<>();
@ -226,6 +274,6 @@ public abstract class BaseEdgeProcessor {
} }
} }
} while (pageData != null && pageData.hasNext()); } 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) { if (ruleChain != null) {
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId); RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
ruleChainMsgConstructor.constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData, edgeVersion); ruleChainMsgConstructor.constructRuleChainMetadataUpdatedMsg(edgeEvent.getTenantId(), msgType, ruleChainMetaData, edgeVersion);
if (ruleChainMetadataUpdateMsg != null) { if (ruleChainMetadataUpdateMsg != null) {
downlinkMsg = DownlinkMsg.newBuilder() downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) .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.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; 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.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.util.JsonUtils; 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.gen.transport.TransportProtos;
import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata; 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 org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -77,14 +82,19 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
private final Gson gson = new Gson(); 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) { public List<ListenableFuture<Void>> processTelemetryFromEdge(TenantId tenantId, CustomerId customerId, EntityDataProto entityData) {
log.trace("[{}] onTelemetryUpdate [{}]", tenantId, entityData); log.trace("[{}] onTelemetryUpdate [{}]", tenantId, entityData);
List<ListenableFuture<Void>> result = new ArrayList<>(); List<ListenableFuture<Void>> result = new ArrayList<>();
EntityId entityId = constructEntityId(entityData); EntityId entityId = constructEntityId(entityData);
if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg() || entityData.hasAttributesUpdatedMsg()) && entityId != null) { 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 = constructBaseMsgMetadata(tenantId, entityId);
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE); metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);
if (entityData.hasPostAttributesMsg()) { if (entityData.hasPostAttributesMsg()) {
result.add(processPostAttributes(tenantId, customerId, entityId, entityData.getPostAttributesMsg(), metaData)); result.add(processPostAttributes(tenantId, customerId, entityId, entityData.getPostAttributesMsg(), metaData));
@ -96,6 +106,20 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
if (entityData.hasPostTelemetryMsg()) { if (entityData.hasPostTelemetryMsg()) {
result.add(processPostTelemetry(tenantId, customerId, entityId, entityData.getPostTelemetryMsg(), metaData)); 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()) { if (entityData.hasAttributeDeleteMsg()) {
result.add(processAttributeDeleteMsg(tenantId, entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType())); result.add(processAttributeDeleteMsg(tenantId, entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType()));
@ -134,21 +158,21 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
return metaData; 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())) { if (EntityType.DEVICE.equals(entityId.getEntityType())) {
DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())); DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
RuleChainId ruleChainId; RuleChainId ruleChainId;
QueueId queueId; String queueName;
if (deviceProfile == null) { if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", entityId); log.warn("[{}] Device profile is null!", entityId);
ruleChainId = null; ruleChainId = null;
queueId = null; queueName = null;
} else { } else {
ruleChainId = deviceProfile.getDefaultRuleChainId(); ruleChainId = deviceProfile.getDefaultRuleChainId();
queueId = deviceProfile.getDefaultQueueId(); queueName = deviceProfile.getDefaultQueueName();
} }
return new ImmutablePair<>(queueId, ruleChainId); return new ImmutablePair<>(queueName, ruleChainId);
} else { } else {
return new ImmutablePair<>(null, null); return new ImmutablePair<>(null, null);
} }
@ -159,10 +183,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + ""); metaData.putValue("ts", tsKv.getTs() + "");
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey(); TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { 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) { private ListenableFuture<Void> processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
SettableFuture<Void> futureToSet = SettableFuture.create(); SettableFuture<Void> futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey(); TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { public void onSuccess(TbQueueMsgMetadata metadata) {
@ -209,10 +229,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
Futures.addCallback(future, new FutureCallback<>() { Futures.addCallback(future, new FutureCallback<>() {
@Override @Override
public void onSuccess(@Nullable List<String> keys) { public void onSuccess(@Nullable List<String> keys) {
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey(); TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { 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 lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device; 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.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService; 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.relation.RelationService;
import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService; 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.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg; import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg; 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.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -81,6 +84,7 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
@Service @Service
@TbCoreComponent
@Slf4j @Slf4j
public class DefaultEdgeRequestsService implements EdgeRequestsService { public class DefaultEdgeRequestsService implements EdgeRequestsService {
@ -100,8 +104,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Autowired @Autowired
private DeviceService deviceService; private DeviceService deviceService;
@Lazy
@Autowired @Autowired
private EntityViewService entityViewService; private TbEntityViewService entityViewService;
@Autowired @Autowired
private DeviceProfileService deviceProfileService; private DeviceProfileService deviceProfileService;
@ -160,6 +165,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
Map<String, Object> entityData = new HashMap<>(); Map<String, Object> entityData = new HashMap<>();
ObjectNode attributes = mapper.createObjectNode(); ObjectNode attributes = mapper.createObjectNode();
for (AttributeKvEntry attr : ssAttributes) { for (AttributeKvEntry attr : ssAttributes) {
if (DefaultDeviceStateService.PERSISTENT_ATTRIBUTES.contains(attr.getKey())) {
continue;
}
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) { if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
attributes.put(attr.getKey(), attr.getBooleanValue().get()); attributes.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) { } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
@ -378,7 +386,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
} }
List<ListenableFuture<Void>> futures = new ArrayList<>(); List<ListenableFuture<Void>> futures = new ArrayList<>();
for (EntityView entityView : entityViews) { 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); EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
futures.add(Futures.transformAsync(future, result -> { futures.add(Futures.transformAsync(future, result -> {
if (Boolean.TRUE.equals(result)) { if (Boolean.TRUE.equals(result)) {
@ -413,11 +421,11 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
} }
private ListenableFuture<Void> saveEdgeEvent(TenantId tenantId, private ListenableFuture<Void> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId, EdgeId edgeId,
EdgeEventType type, EdgeEventType type,
EdgeEventActionType action, EdgeEventActionType action,
EntityId entityId, EntityId entityId,
JsonNode body) { JsonNode body) {
log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
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.springframework.beans.factory.annotation.Value;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType; 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.User;
import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmQuery; 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.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId; 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.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; 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.PageDataIterableByTenantIdEntityId;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.alarm.AlarmService; 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.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.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.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.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
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 java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@ -92,64 +64,18 @@ public abstract class AbstractTbEntityService {
@Autowired @Autowired
protected DbCallbackExecutorService dbExecutor; protected DbCallbackExecutorService dbExecutor;
@Autowired @Autowired(required = false)
protected TbNotificationEntityService notificationEntityService; protected TbNotificationEntityService notificationEntityService;
@Autowired(required = false) @Autowired(required = false)
protected EdgeService edgeService; protected EdgeService edgeService;
@Autowired @Autowired
protected AlarmService alarmService; protected AlarmService alarmService;
@Autowired @Autowired
protected EntityActionService entityActionService;
@Autowired
protected DeviceService deviceService;
@Autowired
protected AssetService assetService;
@Autowired
protected DeviceCredentialsService deviceCredentialsService;
@Autowired
protected TenantService tenantService;
@Autowired
protected CustomerService customerService; protected CustomerService customerService;
@Autowired @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; protected TbClusterService tbClusterService;
@Autowired @Autowired(required = false)
protected OtaPackageStateService otaPackageStateService; private EntitiesVersionControlService vcService;
@Autowired
protected RelationService relationService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected InstallScripts installScripts;
@Autowired
protected UserService userService;
@Autowired
protected TbResourceService resourceService;
@Autowired
protected WidgetsBundleService widgetsBundleService;
protected ListenableFuture<Void> removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) { protected ListenableFuture<Void> removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) {
ListenableFuture<PageData<AlarmInfo>> alarmsFuture = ListenableFuture<PageData<AlarmInfo>> alarmsFuture =
@ -164,15 +90,6 @@ public abstract class AbstractTbEntityService {
}, dbExecutor); }, 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 { protected <T> T checkNotNull(T reference) throws ThingsboardException {
return checkNotNull(reference, "Requested item wasn't found!"); 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) { protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {
if (!edgesEnabled) { if (!edgesEnabled) {
return null; return null;
@ -242,4 +128,26 @@ public abstract class AbstractTbEntityService {
} }
return result; 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; package org.thingsboard.server.service.entitiy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DataConstants; 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.EntityType;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; 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.action.EntityActionService;
import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
@Service @Service
@TbCoreComponent
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultTbNotificationEntityService implements TbNotificationEntityService { public class DefaultTbNotificationEntityService implements TbNotificationEntityService {
private static final ObjectMapper json = new ObjectMapper();
private final EntityActionService entityActionService; private final EntityActionService entityActionService;
private final TbClusterService tbClusterService; private final TbClusterService tbClusterService;
private final GatewayNotificationsService gatewayNotificationsService; private final GatewayNotificationsService gatewayNotificationsService;
@Override @Override
public <E extends HasName, I extends EntityId> void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, public <I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, ActionType actionType,
ActionType actionType, SecurityUser user, Exception e, User user, Exception e, Object... additionalInfo) {
Object... additionalInfo) { logEntityAction(tenantId, entityId, null, null, actionType, user, e, additionalInfo);
logEntityAction(tenantId, entityId, entity, customerId, 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 @Override
public <E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, public <E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType, CustomerId customerId, ActionType actionType,
List<EdgeId> relatedEdgeIds, List<EdgeId> relatedEdgeIds,
SecurityUser user, Object... additionalInfo) { User user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds); sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds);
} }
public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, @Override
CustomerId customerId, public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId,
List<EdgeId> relatedEdgeIds, List<EdgeId> relatedEdgeIds, User user, String body, Object... additionalInfo) {
SecurityUser user,
String body, Object... additionalInfo) {
logEntityAction(tenantId, originatorId, alarm, customerId, ActionType.DELETED, user, additionalInfo); logEntityAction(tenantId, originatorId, alarm, customerId, ActionType.DELETED, user, additionalInfo);
sendAlarmDeleteNotificationMsg(tenantId, alarm, relatedEdgeIds, body); sendAlarmDeleteNotificationMsg(tenantId, alarm, relatedEdgeIds, body);
} }
@Override @Override
public void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, public void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, List<EdgeId> relatedEdgeIds, User user) {
List<EdgeId> relatedEdgeIds, SecurityUser user) {
RuleChainId ruleChainId = ruleChain.getId(); RuleChainId ruleChainId = ruleChain.getId();
logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, null, ruleChainId.toString()); logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, null, ruleChainId.toString());
if (RuleChainType.EDGE.equals(ruleChain.getType())) { if (RuleChainType.EDGE.equals(ruleChain.getType())) {
@ -102,19 +124,18 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override @Override
public <I extends EntityId> void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType) { public <I extends EntityId> void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType) {
sendEntityNotificationMsg(tenantId, entityId, edgeEventActionType); sendEntityNotificationMsg(tenantId, entityId, edgeEventActionType);
} }
@Override @Override
public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
CustomerId customerId, E entity, CustomerId customerId, E entity,
ActionType actionType, ActionType actionType,
EdgeEventActionType edgeActionType, User user, boolean sendToEdge,
SecurityUser user, boolean sendToEdge,
Object... additionalInfo) { Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
if (sendToEdge) { 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, public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
CustomerId customerId, EdgeId edgeId, CustomerId customerId, EdgeId edgeId,
E entity, ActionType actionType, E entity, ActionType actionType,
SecurityUser user, Object... additionalInfo) { User user, Object... additionalInfo) {
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeTypeByActionType(actionType)); sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeTypeByActionType(actionType));
} }
@Override @Override
public void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) { public void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) {
tbClusterService.onTenantChange(tenant, null); tbClusterService.onTenantChange(tenant, null);
tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), event); tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), event);
} }
@ -142,14 +163,14 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override @Override
public void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, public void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId,
Device device, Device oldDevice, ActionType actionType, Device device, Device oldDevice, ActionType actionType,
SecurityUser user, Object... additionalInfo) { User user, Object... additionalInfo) {
tbClusterService.onDeviceUpdated(device, oldDevice); tbClusterService.onDeviceUpdated(device, oldDevice);
logEntityAction(tenantId, deviceId, device, customerId, actionType, user, additionalInfo); logEntityAction(tenantId, deviceId, device, customerId, actionType, user, additionalInfo);
} }
@Override @Override
public void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, 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); gatewayNotificationsService.onDeviceDeleted(device);
tbClusterService.onDeviceDeleted(device, null); tbClusterService.onDeviceDeleted(device, null);
@ -158,7 +179,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override @Override
public void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, 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); tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceCredentials.getDeviceId(), deviceCredentials), null);
sendEntityNotificationMsg(tenantId, deviceId, EdgeEventActionType.CREDENTIALS_UPDATED); sendEntityNotificationMsg(tenantId, deviceId, EdgeEventActionType.CREDENTIALS_UPDATED);
logEntityAction(tenantId, deviceId, device, customerId, ActionType.CREDENTIALS_UPDATED, user, deviceCredentials); logEntityAction(tenantId, deviceId, device, customerId, ActionType.CREDENTIALS_UPDATED, user, deviceCredentials);
@ -166,13 +187,15 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
@Override @Override
public void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId, 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); logEntityAction(tenantId, deviceId, device, customerId, ActionType.ASSIGNED_TO_TENANT, user, additionalInfo);
pushAssignedFromNotification(tenant, newTenantId, device); pushAssignedFromNotification(tenant, newTenantId, device);
} }
@Override @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); logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
if (actionType == ActionType.UPDATED) { if (actionType == ActionType.UPDATED) {
sendEntityNotificationMsg(tenantId, entityId, EdgeEventActionType.UPDATED); sendEntityNotificationMsg(tenantId, entityId, EdgeEventActionType.UPDATED);
@ -180,8 +203,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
} }
@Override @Override
public void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, public void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge,
SecurityUser user, Object... additionalInfo) { ActionType actionType, User user, Object... additionalInfo) {
ComponentLifecycleEvent lifecycleEvent; ComponentLifecycleEvent lifecycleEvent;
EdgeEventActionType edgeEventActionType = null; EdgeEventActionType edgeEventActionType = null;
switch (actionType) { switch (actionType) {
@ -216,69 +239,50 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
} }
@Override @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); logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo);
sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType)); sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType));
} }
@Override @Override
public <E extends HasName, I extends EntityId> void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, 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, ActionType actionType, boolean sendNotifyMsgToEdge, Exception e,
Object... additionalInfo) { Object... additionalInfo) {
notifyEntity(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo); logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo);
if (sendNotifyMsgToEdge) { if (sendNotifyMsgToEdge) {
sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType)); sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType));
} }
} }
@Override @Override
public void notifyCreateOrUpdateOrDeleteRelation(TenantId tenantId, CustomerId customerId, public void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
EntityRelation relation, SecurityUser user, ActionType actionType, Object... additionalInfo) {
ActionType actionType, Exception e, logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, additionalInfo);
Object... additionalInfo) { logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, additionalInfo);
notifyEntity(tenantId, relation.getFrom(), null, customerId, actionType, user, e, additionalInfo); try {
notifyEntity(tenantId, relation.getTo(), null, customerId, actionType, user, e, additionalInfo); if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
if (e == null) { sendNotificationMsgToEdge(tenantId, null, null, JacksonUtil.toString(relation),
try { EdgeEventType.RELATION, edgeTypeByActionType(actionType));
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);
} }
} } catch (Exception e) {
} log.warn("Failed to push relation to core: {}", relation, e);
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);
} }
} }
private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) { 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) { private void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) {
try { try {
sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action); sendNotificationMsgToEdge(tenantId, null, entityId, JacksonUtil.toString(customerId), null, action);
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, 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 { try {
sendDeleteNotificationMsg(tenantId, alarm.getId(), edgeIds, body); sendDeleteNotificationMsg(tenantId, alarm.getId(), edgeIds, body);
} catch (Exception e) { } 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, private <E extends HasName, I extends EntityId> void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, List<EdgeId> edgeIds) {
List<EdgeId> edgeIds) {
try { try {
sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null); sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null);
} catch (Exception e) { } catch (Exception e) {
@ -298,23 +301,25 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, String body) { private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, String body) {
if (edgeIds != null && !edgeIds.isEmpty()) { if (edgeIds != null && !edgeIds.isEmpty()) {
for (EdgeId edgeId : edgeIds) { 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) { 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) { private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body,
tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action); EdgeEventType type, EdgeEventActionType action) {
tbClusterService.sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, type, action);
} }
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
String data = entityToStr(assignedDevice); String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
if (data != null) { 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); tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
} }
} }
@ -326,15 +331,6 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
return metaData; 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) { public static EdgeEventActionType edgeTypeByActionType(ActionType actionType) {
switch (actionType) { switch (actionType) {
case ADDED: case ADDED:
@ -351,6 +347,10 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
return EdgeEventActionType.RELATION_ADD_OR_UPDATE; return EdgeEventActionType.RELATION_ADD_OR_UPDATE;
case RELATION_DELETED: case RELATION_DELETED:
return EdgeEventActionType.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: case ASSIGNED_TO_EDGE:
return EdgeEventActionType.ASSIGNED_TO_EDGE; return EdgeEventActionType.ASSIGNED_TO_EDGE;
case UNASSIGNED_FROM_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; package org.thingsboard.server.service.entitiy;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface SimpleTbEntityService<T> { 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.Device;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.relation.EntityRelation;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List; import java.util.List;
public interface TbNotificationEntityService { public interface TbNotificationEntityService {
<E extends HasName, I extends EntityId> void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, <I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, ActionType actionType, User user,
ActionType actionType, SecurityUser user, Exception e, Exception e, Object... additionalInfo);
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, <E extends HasName, I extends EntityId> void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType, 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, <E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
CustomerId customerId, ActionType actionType, CustomerId customerId, ActionType actionType,
List<EdgeId> relatedEdgeIds, List<EdgeId> relatedEdgeIds,
SecurityUser user, Object... additionalInfo); User user, Object... additionalInfo);
void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId,
CustomerId customerId, List<EdgeId> relatedEdgeIds, List<EdgeId> relatedEdgeIds, User user, String body, Object... additionalInfo);
SecurityUser user, String body, Object... additionalInfo);
void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, 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); <I extends EntityId> void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType);
<E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
CustomerId customerId, E entity, CustomerId customerId, E entity,
ActionType actionType, ActionType actionType,
EdgeEventActionType edgeActionType, User user, boolean sendToEdge,
SecurityUser user, boolean sendToEdge,
Object... additionalInfo); Object... additionalInfo);
<E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId, <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
CustomerId customerId, EdgeId edgeId, CustomerId customerId, EdgeId edgeId,
E entity, ActionType actionType, E entity, ActionType actionType,
SecurityUser user, Object... additionalInfo); User user, Object... additionalInfo);
void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event);
void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event);
void notifyDeleteTenant(Tenant tenant); void notifyDeleteTenant(Tenant tenant);
void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, 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, 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, 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, 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, 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, <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, ActionType actionType, boolean sendNotifyMsgToEdge,
Object... additionalInfo); Exception e, Object... additionalInfo);
void notifyCreateOrUpdateOrDeleteRelation(TenantId tenantId, CustomerId customerId, void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
EntityRelation relation, SecurityUser user, ActionType actionType, Object... additionalInfo);
ActionType actionType, Exception e,
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; 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 lombok.AllArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType; 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.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; 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.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List; import java.util.List;
@Service @Service
@TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService { public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService {
@Override @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; ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = alarm.getTenantId(); TenantId tenantId = alarm.getTenantId();
try { try {
@ -45,46 +47,41 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb
notificationEntityService.notifyCreateOrUpdateAlarm(savedAlarm, actionType, user); notificationEntityService.notifyCreateOrUpdateAlarm(savedAlarm, actionType, user);
return savedAlarm; return savedAlarm;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ALARM), alarm, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM), alarm, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @Override
public void ack(Alarm alarm, SecurityUser user) throws ThingsboardException { public ListenableFuture<Void> ack(Alarm alarm, User user) {
try { long ackTs = System.currentTimeMillis();
long ackTs = System.currentTimeMillis(); ListenableFuture<AlarmOperationResult> future = alarmService.ackAlarm(alarm.getTenantId(), alarm.getId(), ackTs);
alarmService.ackAlarm(user.getTenantId(), alarm.getId(), ackTs).get(); return Futures.transform(future, result -> {
alarm.setAckTs(ackTs); alarm.setAckTs(ackTs);
alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK); alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK);
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user); notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user);
} catch (Exception e) { return null;
throw handleException(e); }, MoreExecutors.directExecutor());
}
} }
@Override @Override
public void clear(Alarm alarm, SecurityUser user) throws ThingsboardException { public ListenableFuture<Void> clear(Alarm alarm, User user) {
try { long clearTs = System.currentTimeMillis();
long clearTs = System.currentTimeMillis(); ListenableFuture<AlarmOperationResult> future = alarmService.clearAlarm(alarm.getTenantId(), alarm.getId(), null, clearTs);
alarmService.clearAlarm(user.getTenantId(), alarm.getId(), null, clearTs).get(); return Futures.transform(future, result -> {
alarm.setClearTs(clearTs); alarm.setClearTs(clearTs);
alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK); alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK);
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user); notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user);
} catch (Exception e) { return null;
throw handleException(e); }, MoreExecutors.directExecutor());
}
} }
@Override @Override
public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { public Boolean delete(Alarm alarm, User user) {
try { TenantId tenantId = alarm.getTenantId();
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, alarm.getOriginator());
notificationEntityService.notifyDeleteAlarm(user.getTenantId(), alarm, alarm.getOriginator(), user.getCustomerId(), notificationEntityService.notifyDeleteAlarm(tenantId, alarm, alarm.getOriginator(), alarm.getCustomerId(),
relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm)); relatedEdgeIds, user, JacksonUtil.toString(alarm));
return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); return alarmService.deleteAlarm(tenantId, alarm.getId()).isSuccessful();
} catch (Exception e) {
throw handleException(e);
}
} }
} }

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

@ -15,17 +15,18 @@
*/ */
package org.thingsboard.server.service.entitiy.alarm; 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.alarm.Alarm;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbAlarmService { 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.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType; 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.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; 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.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List; import java.util.List;
@Service @Service
@TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService { public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService {
private final AssetService assetService;
@Override @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; ActionType actionType = asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = asset.getTenantId(); TenantId tenantId = asset.getTenantId();
try { try {
Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); 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; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), asset, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), asset, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @Override
public ListenableFuture<Void> delete(Asset asset, SecurityUser user) throws ThingsboardException { public ListenableFuture<Void> delete(Asset asset, User user) {
TenantId tenantId = asset.getTenantId(); TenantId tenantId = asset.getTenantId();
AssetId assetId = asset.getId(); AssetId assetId = asset.getId();
try { try {
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId); List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId);
assetService.deleteAsset(tenantId, assetId); assetService.deleteAsset(tenantId, assetId);
notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(),
relatedEdgeIds, user, assetId.toString()); ActionType.DELETED, relatedEdgeIds, user, assetId.toString());
return removeAlarmsByEntityId(tenantId, assetId); return removeAlarmsByEntityId(tenantId, assetId);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), ActionType.DELETED, user, e,
ActionType.DELETED, user, e, assetId.toString()); assetId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
try { try {
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId)); Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, 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; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e,
actionType, user, e, assetId.toString(), customerId.toString()); assetId.toString(), customerId.toString());
throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
try { try {
Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId)); Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId));
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, actionType, user, true, assetId.toString(), customerId.toString(), customer.getName());
true, customerId.toString(), customer.getName());
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e, assetId.toString());
actionType, user, e, assetId.toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
try { try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId())); Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset,
actionType, null, user, false, actionType.toString(), actionType, user, false, actionType.toString(), publicCustomer.getId().toString(), publicCustomer.getName());
publicCustomer.getId().toString(), publicCustomer.getName());
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e, assetId.toString());
actionType, user, e, assetId.toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
try { try {
@ -139,14 +134,14 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType,
actionType, user, e, assetId.toString(), edgeId.toString()); user, e, assetId.toString(), edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
AssetId assetId = asset.getId(); AssetId assetId = asset.getId();
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
@ -155,11 +150,12 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(), notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(),
edgeId, asset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName()); edgeId, asset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName());
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType,
actionType, user, e, assetId.toString(), edgeId.toString()); user, e, assetId.toString(), edgeId.toString());
throw handleException(e); 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 com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Customer; 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.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbAssetService { 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.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType; 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.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.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 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.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List; import java.util.List;
@Service @Service
@TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService { public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService {
@Override @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; ActionType actionType = customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = customer.getTenantId(); TenantId tenantId = customer.getTenantId();
CustomerId customerId = customer.getId();
try { try {
Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer)); 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; return savedCustomer;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), customer, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), customer, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @Override
public void delete(Customer customer, SecurityUser user) throws ThingsboardException { public void delete(Customer customer, User user) {
TenantId tenantId = customer.getTenantId(); TenantId tenantId = customer.getTenantId();
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
try { try {
@ -63,9 +59,9 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements
ActionType.DELETED, relatedEdgeIds, user, customerId.toString()); ActionType.DELETED, relatedEdgeIds, user, customerId.toString());
tbClusterService.broadcastEntityStateChangeEvent(tenantId, customer.getId(), ComponentLifecycleEvent.DELETED); tbClusterService.broadcastEntityStateChangeEvent(tenantId, customer.getId(), ComponentLifecycleEvent.DELETED);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), ActionType.DELETED,
ActionType.DELETED, user, e, customer.getId().toString()); user, e, customerId.toString());
throw handleException(e); 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.Dashboard;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ShortCustomerInfo; 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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -42,23 +42,26 @@ import java.util.Set;
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbDashboardService extends AbstractTbEntityService implements TbDashboardService { public class DefaultTbDashboardService extends AbstractTbEntityService implements TbDashboardService {
private final DashboardService dashboardService;
@Override @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; ActionType actionType = dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = dashboard.getTenantId(); TenantId tenantId = dashboard.getTenantId();
try { try {
Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard));
autoCommit(user, savedDashboard.getId());
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedDashboard.getId(), savedDashboard, notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedDashboard.getId(), savedDashboard,
null, actionType, user); null, actionType, user);
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), dashboard, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), dashboard, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @Override
public void delete(Dashboard dashboard, SecurityUser user) throws ThingsboardException { public void delete(Dashboard dashboard, User user) {
DashboardId dashboardId = dashboard.getId(); DashboardId dashboardId = dashboard.getId();
TenantId tenantId = dashboard.getTenantId(); TenantId tenantId = dashboard.getTenantId();
try { try {
@ -67,66 +70,70 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null, notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null,
ActionType.DELETED, relatedEdgeIds, user, dashboardId.toString()); ActionType.DELETED, relatedEdgeIds, user, dashboardId.toString());
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), ActionType.DELETED, user, e, dashboardId.toString());
ActionType.DELETED, user, e, dashboardId.toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
DashboardId dashboardId = dashboard.getId();
try { try {
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(user.getTenantId(), dashboardId, customerId)); Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboardId, customerId, savedDashboard, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName()); actionType, user, true, dashboardId.toString(), customerId.toString(), customer.getName());
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType,
actionType, user, e, dashboardId.toString(), customerId.toString()); user, e, dashboardId.toString(), customerId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try { try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(user.getTenantId()); Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(user.getTenantId(), dashboardId, publicCustomer.getId())); Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboardId, user.getCustomerId(), savedDashboard, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), savedDashboard,
actionType, null, user, false, dashboardId.toString(), actionType, user, false, dashboardId.toString(),
publicCustomer.getId().toString(), publicCustomer.getName()); publicCustomer.getId().toString(), publicCustomer.getName());
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
actionType, user, e, dashboardId.toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try { try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId()); Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(user.getTenantId(), dashboard.getId(), publicCustomer.getId())); Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboard.getId(), user.getCustomerId(), dashboard, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), dashboard,
actionType, null, user, false, dashboard.getId().toString(), actionType, user, false, dashboardId.toString(),
publicCustomer.getId().toString(), publicCustomer.getName()); publicCustomer.getId().toString(), publicCustomer.getName());
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
actionType, user, e, dashboard.getId().toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = user.getTenantId(); TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try { try {
Set<CustomerId> addedCustomerIds = new HashSet<>(); Set<CustomerId> addedCustomerIds = new HashSet<>();
Set<CustomerId> removedCustomerIds = new HashSet<>(); Set<CustomerId> removedCustomerIds = new HashSet<>();
@ -150,94 +157,105 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
} else { } else {
Dashboard savedDashboard = null; Dashboard savedDashboard = null;
for (CustomerId customerId : addedCustomerIds) { for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId)); savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, 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) { for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); 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, 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; return savedDashboard;
} }
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
actionType, user, e, dashboard.getId().toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
TenantId tenantId = user.getTenantId(); TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try { 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; return dashboard;
} else { } else {
Dashboard savedDashboard = null; Dashboard savedDashboard = null;
for (CustomerId customerId : customerIds) { for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId)); savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerInfo.getTitle()); actionType, user, true, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
} }
return savedDashboard; return savedDashboard;
} }
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
actionType, user, e, dashboard.getId().toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = user.getTenantId(); TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try { 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; return dashboard;
} else { } else {
Dashboard savedDashboard = null; Dashboard savedDashboard = null;
for (CustomerId customerId : customerIds) { for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); 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, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customerInfo.getTitle()); actionType, user, true, dashboardId.toString(), customerId.toString(), customerInfo.getTitle());
} }
return savedDashboard; return savedDashboard;
} }
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
actionType, user, e, dashboard.getId().toString()); throw e;
throw handleException(e);
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
TenantId tenantId = user.getTenantId();
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
try { try {
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(tenantId, dashboardId, edgeId)); 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, savedDashboard, actionType, user, dashboardId.toString(),
edgeId.toString(), edge.getName()); edgeId.toString(), edge.getName());
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
actionType, user, e, dashboardId.toString(), edgeId.toString()); actionType, user, e, dashboardId.toString(), edgeId);
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
TenantId tenantId = dashboard.getTenantId(); TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId(); DashboardId dashboardId = dashboard.getId();
@ -245,30 +263,30 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
try { try {
Dashboard savedDevice = checkNotNull(dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edgeId)); 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, dashboard, actionType, user, dashboardId.toString(),
edgeId.toString(), edge.getName()); edgeId.toString(), edge.getName());
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e,
actionType, user, e, dashboardId.toString(), edgeId.toString()); dashboardId.toString(), edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = dashboard.getTenantId(); TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try { try {
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), customer.getId())); Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboard.getId(), customer.getId(), savedDashboard, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customer.getId(), savedDashboard,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customer.getId().toString(), customer.getName()); actionType, user, true, dashboardId.toString(), customer.getId().toString(), customer.getName());
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString());
actionType, user, e, dashboard.getId().toString()); throw e;
throw handleException(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.Customer;
import org.thingsboard.server.common.data.Dashboard; 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.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; 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.entitiy.SimpleTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Set; 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.Device;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant; 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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials; 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.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult; import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List; import java.util.List;
@ -49,24 +52,32 @@ import java.util.List;
@Slf4j @Slf4j
public class DefaultTbDeviceService extends AbstractTbEntityService implements TbDeviceService { public class DefaultTbDeviceService extends AbstractTbEntityService implements TbDeviceService {
private final DeviceService deviceService;
private final DeviceCredentialsService deviceCredentialsService;
private final ClaimDevicesService claimDevicesService;
private final TenantService tenantService;
@Override @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; ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = device.getTenantId();
try { try {
Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
autoCommit(user, savedDevice.getId());
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(), notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
savedDevice, oldDevice, actionType, user); savedDevice, oldDevice, actionType, user);
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), device, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = device.getTenantId();
try { try {
Device savedDevice = checkNotNull(deviceService.saveDeviceWithCredentials(device, credentials)); Device savedDevice = checkNotNull(deviceService.saveDeviceWithCredentials(device, credentials));
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(), notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
@ -74,13 +85,14 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), device,
throw handleException(e); actionType, user, e);
throw e;
} }
} }
@Override @Override
public ListenableFuture<Void> delete(Device device, SecurityUser user) throws ThingsboardException { public ListenableFuture<Void> delete(Device device, User user) {
TenantId tenantId = device.getTenantId(); TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
try { try {
@ -91,31 +103,31 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
return removeAlarmsByEntityId(tenantId, deviceId); return removeAlarmsByEntityId(tenantId, deviceId);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), ActionType.DELETED,
ActionType.DELETED, user, e, deviceId.toString()); user, e, deviceId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
try { try {
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(user.getTenantId(), deviceId, customerId)); Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice, 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; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), actionType, user,
actionType, user, e, deviceId.toString(), customerId.toString()); e, deviceId.toString(), customerId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = device.getTenantId(); TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
@ -124,55 +136,53 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, actionType, user, true, deviceId.toString(), customerId.toString(), customer.getName());
true, customerId.toString(), customer.getName());
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), actionType,
actionType, user, e, deviceId.toString()); user, e, deviceId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
try { try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId())); Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice, notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice,
actionType, null, user, false, deviceId.toString(), actionType, user, false, deviceId.toString(),
publicCustomer.getId().toString(), publicCustomer.getName()); publicCustomer.getId().toString(), publicCustomer.getName());
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), actionType,
actionType, user, e, deviceId.toString()); user, e, deviceId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException { public DeviceCredentials getDeviceCredentialsByDeviceId(Device device, User user) throws ThingsboardException {
ActionType actionType = ActionType.CREDENTIALS_READ;
TenantId tenantId = device.getTenantId(); TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
try { try {
DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId)); DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId));
notificationEntityService.notifyEntity(tenantId, deviceId, device, device.getCustomerId(), notificationEntityService.logEntityAction(tenantId, deviceId, device, device.getCustomerId(),
actionType, user, null, deviceId.toString()); ActionType.CREDENTIALS_READ, user, deviceId.toString());
return deviceCredentials; return deviceCredentials;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
actionType, user, e, deviceId.toString()); ActionType.CREDENTIALS_READ, user, e, deviceId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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(); TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
try { try {
@ -180,69 +190,63 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
notificationEntityService.notifyUpdateDeviceCredentials(tenantId, deviceId, device.getCustomerId(), device, result, user); notificationEntityService.notifyUpdateDeviceCredentials(tenantId, deviceId, device.getCustomerId(), device, result, user);
return result; return result;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.CREDENTIALS_UPDATED, user, e, deviceCredentials); ActionType.CREDENTIALS_UPDATED, user, e, deviceCredentials);
throw handleException(e); throw e;
} }
} }
@Override @Override
public ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException { public ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, User user) {
try { ListenableFuture<ClaimResult> future = claimDevicesService.claimDevice(device, customerId, secretKey);
ListenableFuture<ClaimResult> future = claimDevicesService.claimDevice(device, customerId, secretKey);
return Futures.transform(future, result -> { return Futures.transform(future, result -> {
if (result != null && result.getResponse().equals(ClaimResponse.SUCCESS)) { if (result != null && result.getResponse().equals(ClaimResponse.SUCCESS)) {
notificationEntityService.notifyEntity(tenantId, device.getId(), result.getDevice(), customerId, notificationEntityService.logEntityAction(tenantId, device.getId(), result.getDevice(), customerId,
ActionType.ASSIGNED_TO_CUSTOMER, user, null, device.getId().toString(), customerId.toString(), ActionType.ASSIGNED_TO_CUSTOMER, user, device.getId().toString(), customerId.toString(),
customerService.findCustomerById(tenantId, customerId).getName()); customerService.findCustomerById(tenantId, customerId).getName());
} }
return result; return result;
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
} catch (Exception e) {
throw handleException(e);
}
} }
@Override @Override
public ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException { public ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, User user) {
try { ListenableFuture<ReclaimResult> future = claimDevicesService.reClaimDevice(tenantId, device);
ListenableFuture<ReclaimResult> future = claimDevicesService.reClaimDevice(tenantId, device);
return Futures.transform(future, result -> { return Futures.transform(future, result -> {
Customer unassignedCustomer = result.getUnassignedCustomer(); Customer unassignedCustomer = result.getUnassignedCustomer();
if (unassignedCustomer != null) { if (unassignedCustomer != null) {
notificationEntityService.notifyEntity(tenantId, device.getId(), device, device.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, user, null, notificationEntityService.logEntityAction(tenantId, device.getId(), device, device.getCustomerId(),
device.getId().toString(), unassignedCustomer.getId().toString(), unassignedCustomer.getName()); ActionType.UNASSIGNED_FROM_CUSTOMER, user, device.getId().toString(),
} unassignedCustomer.getId().toString(), unassignedCustomer.getName());
return result; }
}, MoreExecutors.directExecutor()); return result;
} catch (Exception e) { }, MoreExecutors.directExecutor());
throw handleException(e);
}
} }
@Override @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 tenantId = device.getTenantId();
TenantId newTenantId = newTenant.getId(); TenantId newTenantId = newTenant.getId();
DeviceId deviceId = device.getId();
try { try {
Tenant tenant = tenantService.findTenantById(tenantId); Tenant tenant = tenantService.findTenantById(tenantId);
Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device); 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()); assignedDevice.getCustomerId(), assignedDevice, tenant, user, newTenantId.toString(), newTenant.getName());
return assignedDevice; return assignedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
ActionType.ASSIGNED_TO_TENANT, user, e, newTenantId.toString()); ActionType.ASSIGNED_TO_TENANT, user, e, deviceId.toString());
throw handleException(e); throw e;
} }
} }
@Override @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; ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
try { try {
@ -251,15 +255,14 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
edgeId, savedDevice, actionType, user, deviceId.toString(), edgeId.toString(), edge.getName()); edgeId, savedDevice, actionType, user, deviceId.toString(), edgeId.toString(), edge.getName());
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
actionType, user, e, deviceId.toString(), edgeId.toString()); ActionType.ASSIGNED_TO_EDGE, user, e, deviceId.toString(), edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException { public Device unassignDeviceFromEdge(Device device, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
TenantId tenantId = device.getTenantId(); TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
@ -267,12 +270,12 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId)); Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, device.getCustomerId(), 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; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE),
actionType, user, e, deviceId.toString(), edgeId.toString()); ActionType.UNASSIGNED_FROM_EDGE, user, e, deviceId.toString(), edgeId.toString());
throw handleException(e); 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.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant; 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.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; 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.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.claim.ClaimResult; import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult; import org.thingsboard.server.dao.device.claim.ReclaimResult;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbDeviceService { 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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.entitiy.deviceProfile; package org.thingsboard.server.service.entitiy.device.profile;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType; 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.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; 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; import java.util.Objects;
@ -36,8 +38,12 @@ import java.util.Objects;
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
public class DefaultTbDeviceProfileService extends AbstractTbEntityService implements TbDeviceProfileService { public class DefaultTbDeviceProfileService extends AbstractTbEntityService implements TbDeviceProfileService {
private final DeviceProfileService deviceProfileService;
private final OtaPackageStateService otaPackageStateService;
@Override @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; ActionType actionType = deviceProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = deviceProfile.getTenantId(); TenantId tenantId = deviceProfile.getTenantId();
try { try {
@ -54,23 +60,24 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple
} }
} }
DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
autoCommit(user, savedDeviceProfile.getId());
tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedDeviceProfile.getId(), tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedDeviceProfile.getId(),
actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged); 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; return savedDeviceProfile;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.DEVICE_PROFILE), deviceProfile, user, actionType, false, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), deviceProfile, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @Override
public void delete(DeviceProfile deviceProfile, SecurityUser user) throws ThingsboardException { public void delete(DeviceProfile deviceProfile, User user) {
DeviceProfileId deviceProfileId = deviceProfile.getId(); DeviceProfileId deviceProfileId = deviceProfile.getId();
TenantId tenantId = deviceProfile.getTenantId(); TenantId tenantId = deviceProfile.getTenantId();
try { try {
@ -78,34 +85,35 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple
tbClusterService.onDeviceProfileDelete(deviceProfile, null); tbClusterService.onDeviceProfileDelete(deviceProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, deviceProfileId, ComponentLifecycleEvent.DELETED); 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) { } catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.DEVICE_PROFILE), null, user, ActionType.DELETED, false, e, deviceProfileId.toString()); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), ActionType.DELETED,
throw handleException(e); user, e, deviceProfileId.toString());
throw e;
} }
} }
@Override @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(); TenantId tenantId = deviceProfile.getTenantId();
DeviceProfileId deviceProfileId = deviceProfile.getId();
try { try {
if (deviceProfileService.setDefaultDeviceProfile(tenantId, deviceProfileId)) {
if (deviceProfileService.setDefaultDeviceProfile(tenantId, deviceProfile.getId())) {
if (previousDefaultDeviceProfile != null) { if (previousDefaultDeviceProfile != null) {
previousDefaultDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, previousDefaultDeviceProfile.getId()); previousDefaultDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, previousDefaultDeviceProfile.getId());
notificationEntityService.notifyEntity(tenantId, previousDefaultDeviceProfile.getId(), previousDefaultDeviceProfile, null, notificationEntityService.logEntityAction(tenantId, previousDefaultDeviceProfile.getId(), previousDefaultDeviceProfile,
ActionType.UPDATED, user, null); ActionType.UPDATED, user);
} }
deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfile.getId()); deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
notificationEntityService.notifyEntity(tenantId, deviceProfile.getId(), deviceProfile, null, notificationEntityService.logEntityAction(tenantId, deviceProfileId, deviceProfile, ActionType.UPDATED, user);
ActionType.UPDATED, user, null);
} }
return deviceProfile; return deviceProfile;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE_PROFILE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), ActionType.UPDATED,
ActionType.UPDATED, user, e, deviceProfile.getId().toString()); user, e, deviceProfileId.toString());
throw handleException(e); 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.DeviceProfile;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.entitiy.SimpleTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbDeviceProfileService extends SimpleTbEntityService<DeviceProfile> { 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.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType; 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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException; 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.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
@AllArgsConstructor @AllArgsConstructor
@TbCoreComponent @TbCoreComponent
@ -38,8 +40,11 @@ import org.thingsboard.server.service.security.model.SecurityUser;
@Slf4j @Slf4j
public class DefaultTbEdgeService extends AbstractTbEntityService implements TbEdgeService { public class DefaultTbEdgeService extends AbstractTbEntityService implements TbEdgeService {
private final EdgeNotificationService edgeNotificationService;
private final RuleChainService ruleChainService;
@Override @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; ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = edge.getTenantId(); TenantId tenantId = edge.getTenantId();
try { try {
@ -56,95 +61,89 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e); notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE), edge, actionType, user, e);
throw handleException(e); throw e;
} }
} }
@Override @Override
public void delete(Edge edge, SecurityUser user) throws ThingsboardException { public void delete(Edge edge, User user) {
ActionType actionType = ActionType.DELETED;
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
TenantId tenantId = edge.getTenantId(); TenantId tenantId = edge.getTenantId();
try { try {
edgeService.deleteEdge(tenantId, edgeId); 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) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE), ActionType.DELETED,
user, e, edgeId.toString()); user, e, edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException { public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
try { try {
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId)); Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId));
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, ActionType.ASSIGNED_TO_CUSTOMER, user,
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
edgeId.toString(), customerId.toString(), customer.getName()); edgeId.toString(), customerId.toString(), customer.getName());
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
actionType, user, e, edgeId.toString(), customerId.toString()); ActionType.ASSIGNED_TO_CUSTOMER, user, e, edgeId.toString(), customerId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException { public Edge unassignEdgeFromCustomer(Edge edge, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
TenantId tenantId = edge.getTenantId(); TenantId tenantId = edge.getTenantId();
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
try { try {
Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(tenantId, edgeId)); 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()); edgeId.toString(), customerId.toString(), customer.getName());
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
actionType, user, e, edgeId.toString()); ActionType.UNASSIGNED_FROM_CUSTOMER, user, e, edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException { public Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
CustomerId customerId = publicCustomer.getId();
try { try {
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
CustomerId customerId = publicCustomer.getId();
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId)); 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()); edgeId.toString(), customerId.toString(), publicCustomer.getName());
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
actionType, user, e, edgeId.toString()); ActionType.ASSIGNED_TO_CUSTOMER, user, e, edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException { public Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, User user) throws Exception {
ActionType actionType = ActionType.UPDATED;
TenantId tenantId = edge.getTenantId(); TenantId tenantId = edge.getTenantId();
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
try { try {
Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, ruleChainId); 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; return updatedEdge;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE),
actionType, user, e, edgeId.toString()); ActionType.UPDATED, user, e, edgeId.toString());
throw handleException(e); 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; package org.thingsboard.server.service.entitiy.edge;
import org.thingsboard.server.common.data.Customer; 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.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbEdgeService { 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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.entitiy.entityRelation; package org.thingsboard.server.service.entitiy.entity.relation;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; 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.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; 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.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
@Service @Service
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
public class DefaultTbEntityRelationService extends AbstractTbEntityService implements TbEntityRelationService { public class DefaultTbEntityRelationService extends AbstractTbEntityService implements TbEntityRelationService {
private final RelationService relationService;
@Override @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 { try {
relationService.saveRelation(tenantId, relation); relationService.saveRelation(tenantId, relation);
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId, notificationEntityService.notifyRelation(tenantId, customerId,
relation, user, ActionType.RELATION_ADD_OR_UPDATE, null, relation); relation, user, ActionType.RELATION_ADD_OR_UPDATE, relation);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId, notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId,
relation, user, ActionType.RELATION_ADD_OR_UPDATE, e, relation); ActionType.RELATION_ADD_OR_UPDATE, user, e, relation);
throw handleException(e); notificationEntityService.logEntityAction(tenantId, relation.getTo(), null, customerId,
ActionType.RELATION_ADD_OR_UPDATE, user, e, relation);
throw e;
} }
} }
@Override @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 { 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) { if (!found) {
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
} }
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId, notificationEntityService.notifyRelation(tenantId, customerId,
relation, user, ActionType.RELATION_DELETED, null, relation); relation, user, ActionType.RELATION_DELETED, relation);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDeleteRelation (tenantId, customerId, notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId,
relation, user, ActionType.RELATION_DELETED, e, relation); ActionType.RELATION_DELETED, user, e, relation);
throw handleException(e); notificationEntityService.logEntityAction(tenantId, relation.getTo(), null, customerId,
ActionType.RELATION_DELETED, user, e, relation);
throw e;
} }
} }
@Override @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 { try {
relationService.deleteEntityRelations(tenantId, entityId); 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) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user, e); notificationEntityService.logEntityAction(tenantId, entityId, null, customerId,
throw handleException(e); 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface TbEntityRelationService { 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
@ -23,13 +23,14 @@ import com.google.common.util.concurrent.SettableFuture;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; 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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId; 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.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry; 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.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; 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 javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
@Service @Service
@TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
public class DefaultTbEntityViewService extends AbstractTbEntityService implements TbEntityViewService { public class DefaultTbEntityViewService extends AbstractTbEntityService implements TbEntityViewService {
private final EntityViewService entityViewService;
private final AttributesService attributesService;
private final TelemetrySubscriptionService tsSubService;
private final TimeseriesService tsService; private final TimeseriesService tsService;
final Map<TenantId, Map<EntityId, List<EntityView>>> localCache = new ConcurrentHashMap<>();
@Override @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; ActionType actionType = entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = entityView.getTenantId();
try { 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)); EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
if (savedEntityView.getKeys() != null) { this.updateEntityViewAttributes(tenantId, savedEntityView, existingEntityView, user);
if (savedEntityView.getKeys().getAttributes() != null) { autoCommit(user, savedEntityView.getId());
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);
}
}
notificationEntityService.notifyCreateOrUpdateEntity(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView, notificationEntityService.notifyCreateOrUpdateEntity(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView,
null, actionType, user); 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; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.ENTITY_VIEW), entityView, null, actionType, user, e); notificationEntityService.logEntityAction(user.getTenantId(), emptyId(EntityType.ENTITY_VIEW), entityView, actionType, user, e);
throw handleException(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 @Override
public void delete(EntityView entityView, SecurityUser user) throws ThingsboardException { public void delete(EntityView entityView, User user) throws ThingsboardException {
TenantId tenantId = entityView.getTenantId(); TenantId tenantId = entityView.getTenantId();
EntityViewId entityViewId = entityView.getId(); EntityViewId entityViewId = entityView.getId();
try { try {
@ -114,99 +133,142 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
entityViewService.deleteEntityView(tenantId, entityViewId); entityViewService.deleteEntityView(tenantId, entityViewId);
notificationEntityService.notifyDeleteEntity(tenantId, entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED, notificationEntityService.notifyDeleteEntity(tenantId, entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED,
relatedEdgeIds, user, entityViewId.toString()); relatedEdgeIds, user, entityViewId.toString());
localCache.computeIfAbsent(tenantId, (k) -> new ConcurrentReferenceHashMap<>()).clear();
tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityViewId, ComponentLifecycleEvent.DELETED);
} catch (Exception e) { } 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()); ActionType.DELETED, user, e, entityViewId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, SecurityUser user) throws ThingsboardException { public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
try { try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, entityViewId, customerId)); EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, entityViewId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customerId, savedEntityView, 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; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
actionType, user, e, entityViewId.toString(), customerId.toString()); ActionType.ASSIGNED_TO_CUSTOMER, user, e, entityViewId.toString(), customerId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public EntityView assignEntityViewToPublicCustomer(TenantId tenantId, CustomerId customerId, Customer publicCustomer, public EntityView assignEntityViewToPublicCustomer(TenantId tenantId, CustomerId customerId, Customer publicCustomer,
EntityViewId entityViewId, SecurityUser user) throws ThingsboardException { EntityViewId entityViewId, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
try { try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId,
entityViewId, publicCustomer.getId())); entityViewId, publicCustomer.getId()));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customerId, savedEntityView, 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()); publicCustomer.getId().toString(), publicCustomer.getName());
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
actionType, user, e, entityViewId.toString()); ActionType.ASSIGNED_TO_CUSTOMER, user, e, entityViewId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, SecurityUser user) throws ThingsboardException { public EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edgeId));
try { try {
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId, 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()); edgeId.toString(), edge.getName());
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
actionType, user, e, entityViewId.toString(), edgeId.toString()); ActionType.ASSIGNED_TO_EDGE, user, e, entityViewId.toString(), edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView, public EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView,
Edge edge, SecurityUser user) throws ThingsboardException { Edge edge, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
EntityViewId entityViewId = entityView.getId(); EntityViewId entityViewId = entityView.getId();
EdgeId edgeId = edge.getId(); EdgeId edgeId = edge.getId();
try { try {
EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(tenantId, entityViewId, edgeId)); EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(tenantId, entityViewId, edgeId));
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId, notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId,
edgeId, entityView, actionType, user, entityViewId.toString(), edgeId, entityView, ActionType.UNASSIGNED_FROM_EDGE, user, entityViewId.toString(),
edgeId.toString(), edge.getName()); edgeId.toString(), edge.getName());
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
actionType, user, e, entityViewId.toString(), edgeId.toString()); ActionType.UNASSIGNED_FROM_EDGE, user, e, entityViewId.toString(), edgeId.toString());
throw handleException(e); throw e;
} }
} }
@Override @Override
public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, SecurityUser user) throws ThingsboardException { public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException {
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
try { try {
EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId)); EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customer.getId(), savedEntityView, 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; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ENTITY_VIEW), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW),
actionType, user, e, entityViewId.toString()); ActionType.UNASSIGNED_FROM_CUSTOMER, user, e, entityViewId.toString());
throw handleException(e); 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(); EntityViewId entityId = entityView.getId();
if (keys != null && !keys.isEmpty()) { if (keys != null && !keys.isEmpty()) {
ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getTenantId(), entityView.getEntityId(), scope, keys); 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(); long lastUpdateTs = attributeKvEntry.getLastUpdateTs();
return startTime == 0 && endTime == 0 || return startTime == 0 && endTime == 0 ||
(endTime == 0 && startTime < lastUpdateTs) || (endTime == 0 && startTime < lastUpdateTs) ||
(startTime == 0 && endTime > lastUpdateTs) (startTime == 0 && endTime > lastUpdateTs) ||
? true : startTime < lastUpdateTs && endTime > lastUpdateTs; (startTime < lastUpdateTs && endTime > lastUpdateTs);
}).collect(Collectors.toList()); }).collect(Collectors.toList());
tsSubService.saveAndNotify(entityView.getTenantId(), entityId, scope, attributes, new FutureCallback<Void>() { tsSubService.saveAndNotify(entityView.getTenantId(), entityId, scope, attributes, new FutureCallback<Void>() {
@Override @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(); EntityViewId entityId = entityView.getId();
List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ? List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ?
entityView.getKeys().getTimeseries() : Collections.emptyList(); 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(); long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs();
ListenableFuture<List<String>> keysFuture; ListenableFuture<List<String>> keysFuture;
if (keys.isEmpty()) { 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()); entityView.getEntityId()), latest -> latest.stream().map(TsKvEntry::getKey).collect(Collectors.toList()), MoreExecutors.directExecutor());
} else { } else {
keysFuture = Futures.immediateFuture(keys); keysFuture = Futures.immediateFuture(keys);
@ -267,7 +329,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
ListenableFuture<List<TsKvEntry>> latestFuture = Futures.transformAsync(keysFuture, fetchKeys -> { 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()); List<ReadTsKvQuery> queries = fetchKeys.stream().filter(key -> !isBlank(key)).map(key -> new BaseReadTsKvQuery(key, startTs, endTs, 1, "DESC")).collect(Collectors.toList());
if (!queries.isEmpty()) { if (!queries.isEmpty()) {
return tsService.findAll(user.getTenantId(), entityView.getEntityId(), queries); return tsService.findAll(tenantId, entityView.getEntityId(), queries);
} else { } else {
return Futures.immediateFuture(null); return Futures.immediateFuture(null);
} }
@ -288,7 +350,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
}, MoreExecutors.directExecutor()); }, 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(); EntityViewId entityId = entityView.getId();
SettableFuture<Void> resultFuture = SettableFuture.create(); SettableFuture<Void> resultFuture = SettableFuture.create();
if (keys != null && !keys.isEmpty()) { if (keys != null && !keys.isEmpty()) {
@ -319,7 +381,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
return resultFuture; 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(); EntityViewId entityId = entityView.getId();
SettableFuture<Void> resultFuture = SettableFuture.create(); SettableFuture<Void> resultFuture = SettableFuture.create();
if (keys != null && !keys.isEmpty()) { if (keys != null && !keys.isEmpty()) {
@ -337,7 +399,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
try { try {
logTimeseriesDeleted(entityView.getTenantId(),user, entityId, keys, t); logTimeseriesDeleted(entityView.getTenantId(), user, entityId, keys, t);
} catch (ThingsboardException e) { } catch (ThingsboardException e) {
log.error("Failed to log timeseries delete", e); log.error("Failed to log timeseries delete", e);
} }
@ -370,16 +432,16 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
return resultFuture; return resultFuture;
} }
private void logAttributesUpdated(TenantId tenantId, SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException { private void logAttributesUpdated(TenantId tenantId, User 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); 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 { private void logAttributesDeleted(TenantId tenantId, User 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); 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 { private void logTimeseriesDeleted(TenantId tenantId, User user, EntityId entityId, List<String> keys, Throwable e) throws ThingsboardException {
notificationEntityService.notifyEntity(tenantId, entityId, null, null, ActionType.TIMESERIES_DELETED, user, toException(e), keys); notificationEntityService.logEntityAction(tenantId, entityId, ActionType.TIMESERIES_DELETED, user, toException(e), keys);
} }
public static Exception toException(Throwable error) { 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.Customer;
import org.thingsboard.server.common.data.EntityView; 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.edge.Edge;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; 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.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId; 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, void updateEntityViewAttributes(TenantId tenantId, EntityView savedEntityView, EntityView oldEntityView, User user) throws ThingsboardException;
SecurityUser 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, 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, EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView, Edge edge, User user) throws ThingsboardException;
SecurityUser user) throws ThingsboardException;
EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView, EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException;
Edge edge, SecurityUser user) throws ThingsboardException;
EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId);
SecurityUser user) throws ThingsboardException;
} }

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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.entitiy.otaPackageController; package org.thingsboard.server.service.entitiy.ota;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; 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.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -39,40 +40,31 @@ import java.nio.ByteBuffer;
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
public class DefaultTbOtaPackageService extends AbstractTbEntityService implements TbOtaPackageService { public class DefaultTbOtaPackageService extends AbstractTbEntityService implements TbOtaPackageService {
private final OtaPackageService otaPackageService;
@Override @Override
public OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, SecurityUser user) throws ThingsboardException { public OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, User user) throws ThingsboardException {
TenantId tenantId = saveOtaPackageInfoRequest.getTenantId();
ActionType actionType = saveOtaPackageInfoRequest.getId() == null ? ActionType.ADDED : ActionType.UPDATED; ActionType actionType = saveOtaPackageInfoRequest.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = saveOtaPackageInfoRequest.getTenantId();
try { try {
OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(new OtaPackageInfo(saveOtaPackageInfoRequest), saveOtaPackageInfoRequest.isUsesUrl()); 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; return savedOtaPackageInfo;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.OTA_PACKAGE), saveOtaPackageInfoRequest, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), saveOtaPackageInfoRequest,
actionType, user, e); actionType, user, e);
throw handleException(e); throw 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);
} }
} }
@Override @Override
public OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm, 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(); TenantId tenantId = otaPackageInfo.getTenantId();
OtaPackageId otaPackageId = otaPackageInfo.getId(); OtaPackageId otaPackageId = otaPackageInfo.getId();
try { try {
@ -95,13 +87,28 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen
otaPackage.setData(ByteBuffer.wrap(data)); otaPackage.setData(ByteBuffer.wrap(data));
otaPackage.setDataSize((long) data.length); otaPackage.setDataSize((long) data.length);
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage); OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage);
notificationEntityService.notifyEntity(tenantId, savedOtaPackage.getId(), savedOtaPackage, null, notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackage.getId(),
ActionType.UPDATED, user, null); savedOtaPackage, user, ActionType.UPDATED, true, null);
return savedOtaPackage; return savedOtaPackage;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.OTA_PACKAGE), null, null, notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), ActionType.UPDATED,
ActionType.UPDATED, user, e, otaPackageId.toString()); user, e, otaPackageId.toString());
throw handleException(e); 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; 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; OtaPackageInfo save(SaveOtaPackageInfoRequest saveOtaPackageInfoRequest, User user) throws ThingsboardException;
void delete(OtaPackageInfo otaPackageInfo, SecurityUser user) throws ThingsboardException;
OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm, 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.cluster.TbClusterService;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.TenantProfile; 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.QueueId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageLink; 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.data.tenant.profile.TenantProfileQueueConfiguration;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.dao.device.DeviceProfileService; 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.TbQueueAdmin;
import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.queue.scheduler.SchedulerComponent;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -46,12 +48,11 @@ import java.util.stream.Collectors;
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService { public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService {
private static final String MAIN = "Main";
private static final long DELETE_DELAY = 30; private static final long DELETE_DELAY = 30;
private final QueueService queueService;
private final TbClusterService tbClusterService; private final TbClusterService tbClusterService;
private final TbQueueAdmin tbQueueAdmin; private final TbQueueAdmin tbQueueAdmin;
private final DeviceProfileService deviceProfileService;
private final SchedulerComponent scheduler; private final SchedulerComponent scheduler;
@Override @Override
@ -74,6 +75,8 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
onQueueUpdated(savedQueue, oldQueue); onQueueUpdated(savedQueue, oldQueue);
} }
notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), savedQueue.getId(), create ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return savedQueue; return savedQueue;
} }
@ -146,6 +149,8 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
} }
} }
}, DELETE_DELAY, TimeUnit.SECONDS); }, DELETE_DELAY, TimeUnit.SECONDS);
notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), queue.getId(), EdgeEventActionType.DELETED);
} }
@Override @Override
@ -198,35 +203,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
} }
tenantIds.forEach(tenantId -> { tenantIds.forEach(tenantId -> {
Map<QueueId, List<DeviceProfile>> deviceProfileQueues; toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key))));
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);
}
});
}
toUpdate.forEach(key -> { toUpdate.forEach(key -> {
Queue queueToUpdate = new Queue(tenantId, newQueues.get(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.setId(foundQueue.getId());
queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); queueToUpdate.setCreatedTime(foundQueue.getCreatedTime());
if (queueToUpdate.equals(foundQueue)) { if (!queueToUpdate.equals(foundQueue)) {
//Queue not changed
} else {
saveQueue(queueToUpdate); saveQueue(queueToUpdate);
} }
}); });
@ -244,26 +219,9 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
toRemove.forEach(q -> { toRemove.forEach(q -> {
Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q); Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q);
QueueId queueIdForRemove = queue.getId(); 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); 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.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile; 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.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 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.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.entitiy.queue.TbQueueService; import org.thingsboard.server.service.entitiy.queue.TbQueueService;
import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.install.InstallScripts;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Service @Service
@TbCoreComponent @TbCoreComponent
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultTbTenantService extends AbstractTbEntityService implements TbTenantService { public class DefaultTbTenantService extends AbstractTbEntityService implements TbTenantService {
private final TenantService tenantService;
private final TbTenantProfileCache tenantProfileCache;
private final InstallScripts installScripts; private final InstallScripts installScripts;
private final TbQueueService tbQueueService; private final TbQueueService tbQueueService;
private final TenantProfileService tenantProfileService; private final TenantProfileService tenantProfileService;
private final EntitiesVersionControlService versionControlService;
@Override @Override
public Tenant save(Tenant tenant) throws ThingsboardException { public Tenant save(Tenant tenant) throws Exception {
try { boolean created = tenant.getId() == null;
boolean created = tenant.getId() == null; Tenant oldTenant = !created ? tenantService.findTenantById(tenant.getId()) : null;
Tenant oldTenant = !created ? tenantService.findTenantById(tenant.getId()) : null;
Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant)); Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant));
if (created) { if (created) {
installScripts.createDefaultRuleChains(savedTenant.getId()); installScripts.createDefaultRuleChains(savedTenant.getId());
installScripts.createDefaultEdgeRuleChains(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);
} }
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 @Override
public void delete(Tenant tenant) throws ThingsboardException { public void delete(Tenant tenant) throws Exception {
try { TenantId tenantId = tenant.getId();
TenantId tenantId = tenant.getId(); tenantService.deleteTenant(tenantId);
tenantService.deleteTenant(tenantId); tenantProfileCache.evict(tenantId);
tenantProfileCache.evict(tenantId); notificationEntityService.notifyDeleteTenant(tenant);
notificationEntityService.notifyDeleteTenant(tenant); versionControlService.deleteVersionControlSettings(tenantId).get(1, TimeUnit.MINUTES);
} catch (Exception e) {
throw handleException(e);
}
} }
} }

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

@ -16,12 +16,11 @@
package org.thingsboard.server.service.entitiy.tenant; package org.thingsboard.server.service.entitiy.tenant;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.exception.ThingsboardException;
public interface TbTenantService { 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.TenantProfile; 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.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.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent; 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.entitiy.queue.TbQueueService;
import java.util.List; import java.util.List;
@ -31,20 +35,31 @@ import java.util.List;
@Service @Service
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbTenantProfileService implements TbTenantProfileService { public class DefaultTbTenantProfileService extends AbstractTbEntityService implements TbTenantProfileService {
private final TbQueueService tbQueueService; private final TbQueueService tbQueueService;
private final TenantProfileService tenantProfileService; private final TenantProfileService tenantProfileService;
private final TenantService tenantService; private final TenantService tenantService;
private final TbTenantProfileCache tenantProfileCache;
@Override @Override
public TenantProfile saveTenantProfile(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) { public TenantProfile save(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) throws ThingsboardException {
TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(tenantId, tenantProfile); TenantProfile savedTenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(tenantId, tenantProfile));
if (oldTenantProfile != null && savedTenantProfile.isIsolatedTbRuleEngine()) { if (oldTenantProfile != null && savedTenantProfile.isIsolatedTbRuleEngine()) {
List<TenantId> tenantIds = tenantService.findTenantIdsByTenantProfileId(savedTenantProfile.getId()); List<TenantId> tenantIds = tenantService.findTenantIdsByTenantProfileId(savedTenantProfile.getId());
tbQueueService.updateQueuesByTenants(tenantIds, savedTenantProfile, oldTenantProfile); 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; 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.TenantId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserCredentials; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.system.SystemSecurityService; import org.thingsboard.server.service.security.system.SystemSecurityService;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -44,12 +44,13 @@ import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATT
@Slf4j @Slf4j
public class DefaultUserService extends AbstractTbEntityService implements TbUserService { public class DefaultUserService extends AbstractTbEntityService implements TbUserService {
private final UserService userService;
private final MailService mailService; private final MailService mailService;
private final SystemSecurityService systemSecurityService; private final SystemSecurityService systemSecurityService;
@Override @Override
public User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail, 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; ActionType actionType = tbUser.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
try { try {
boolean sendEmail = tbUser.getId() == null && sendActivationMail; boolean sendEmail = tbUser.getId() == null && sendActivationMail;
@ -71,25 +72,24 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
savedUser, user, actionType, true, null); savedUser, user, actionType, true, null);
return savedUser; return savedUser;
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.USER), notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), tbUser, actionType, user, e);
tbUser, user, actionType, false, e); throw e;
throw handleException(e);
} }
} }
@Override @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(); UserId userId = tbUser.getId();
try { try {
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, userId); List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, userId);
userService.deleteUser(tenantId, userId); userService.deleteUser(tenantId, userId);
notificationEntityService.notifyDeleteEntity(tenantId, userId, tbUser, customerId, notificationEntityService.notifyDeleteEntity(tenantId, userId, tbUser, customerId,
ActionType.DELETED, relatedEdgeIds, user, userId.toString()); ActionType.DELETED, relatedEdgeIds, user, userId.toString());
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, emptyId(EntityType.USER), notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER),
null, user, ActionType.DELETED, false, e, userId.toString()); ActionType.DELETED, user, e, userId.toString());
throw handleException(e); 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.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
public interface TbUserService { 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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.entitiy.widgetsBundle; package org.thingsboard.server.service.entitiy.widgets.bundle;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service; 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.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.widget.WidgetsBundle; 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
@Service @Service
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultWidgetsBundleService extends AbstractTbEntityService implements TbWidgetsBundleService{ public class DefaultWidgetsBundleService extends AbstractTbEntityService implements TbWidgetsBundleService {
private final WidgetsBundleService widgetsBundleService;
@Override @Override
public WidgetsBundle save(WidgetsBundle widgetsBundle, SecurityUser user) throws ThingsboardException { public WidgetsBundle save(WidgetsBundle widgetsBundle, User user) throws Exception {
try {
WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), savedWidgetsBundle.getId(), autoCommit(user, savedWidgetsBundle.getId());
widgetsBundle.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), savedWidgetsBundle.getId(),
widgetsBundle.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return savedWidgetsBundle; return savedWidgetsBundle;
} catch (Exception e) {
throw handleException(e);
}
} }
@Override @Override
public void delete(WidgetsBundle widgetsBundle, SecurityUser user) throws ThingsboardException { public void delete(WidgetsBundle widgetsBundle) throws ThingsboardException {
try { widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId());
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId()); notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), widgetsBundle.getId(),
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), widgetsBundle.getId(), EdgeEventActionType.DELETED);
EdgeEventActionType.DELETED);
} catch (Exception e) {
throw handleException(e);
}
} }
} }

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

Loading…
Cancel
Save