Browse Source

Merge branch 'master' into fix_bug_californium_3_11

pull/10462/head
Viacheslav Klimov 3 years ago
committed by GitHub
parent
commit
ae2533162e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .github/ISSUE_TEMPLATE/---bug-report.md
  2. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  3. 2
      .github/ISSUE_TEMPLATE/question.md
  4. 111
      application/src/main/data/json/demo/dashboards/rule_engine_statistics.json
  5. 32
      application/src/main/data/upgrade/3.6.3/schema_update.sql
  6. 6
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  7. 3
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  8. 6
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  9. 8
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  10. 1
      application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java
  11. 7
      application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
  12. 8
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  13. 75
      application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java
  14. 41
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  15. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java
  16. 32
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/oauth2/OAuth2MsgConstructor.java
  17. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java
  18. 56
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java
  19. 248
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
  20. 3
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java
  21. 20
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java
  22. 63
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/oauth2/OAuth2EdgeProcessor.java
  23. 27
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessor.java
  24. 1
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantEdgeProcessor.java
  25. 11
      application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java
  26. 16
      application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
  27. 11
      application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java
  28. 2
      application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
  29. 8
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  30. 4
      application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java
  31. 47
      application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java
  32. 149
      application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java
  33. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  34. 76
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  35. 1
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java
  36. 4
      application/src/main/resources/thingsboard.yml
  37. 53
      application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java
  38. 21
      application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java
  39. 38
      application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java
  40. 51
      application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java
  41. 2
      application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java
  42. 3
      application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
  43. 15
      application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java
  44. 113
      application/src/test/java/org/thingsboard/server/edge/OAuth2EdgeTest.java
  45. 6
      application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java
  46. 25
      application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorTest.java
  47. 40
      application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessorTest.java
  48. 80
      application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java
  49. 2
      application/src/test/resources/logback-test.xml
  50. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
  51. 1
      common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java
  52. 37
      common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueStatsService.java
  53. 6
      common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
  54. 3
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
  55. 2
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
  56. 43
      common/data/src/main/java/org/thingsboard/server/common/data/id/QueueStatsId.java
  57. 2
      common/data/src/main/java/org/thingsboard/server/common/data/id/UUIDBased.java
  58. 2
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java
  59. 2
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java
  60. 26
      common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java
  61. 30
      common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java
  62. 39
      common/data/src/main/java/org/thingsboard/server/common/data/queue/QueueStats.java
  63. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadRequest.java
  64. 6
      common/edge-api/src/main/proto/edge.proto
  65. 150
      common/proto/src/main/java/org/thingsboard/server/common/util/KvProtoUtil.java
  66. 65
      common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java
  67. 1
      common/proto/src/main/proto/queue.proto
  68. 118
      common/proto/src/test/java/org/thingsboard/server/common/util/KvProtoUtilTest.java
  69. 30
      common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java
  70. 24
      common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java
  71. 4
      common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java
  72. 9
      common/script/script-api/src/main/java/org/thingsboard/script/api/js/NashornJsInvokeService.java
  73. 71
      common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java
  74. 82
      common/transport/http/src/test/java/org/thingsboard/server/transport/http/DeviceApiControllerTest.java
  75. 16
      common/transport/http/src/test/resources/logback-test.xml
  76. 18
      dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
  77. 2
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
  78. 4
      dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java
  79. 20
      dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
  80. 24
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java
  81. 81
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  82. 6
      dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeUtils.java
  83. 8
      dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java
  84. 4
      dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java
  85. 14
      dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java
  86. 14
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
  87. 32
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  88. 2
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java
  89. 4
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java
  90. 26
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  91. 68
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  92. 64
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
  93. 66
      dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
  94. 68
      dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
  95. 9
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  96. 5
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java
  97. 69
      dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueStatsEntity.java
  98. 6
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ConfigTemplateServiceImpl.java
  99. 12
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java
  100. 1
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java

2
.github/ISSUE_TEMPLATE/---bug-report.md

@ -3,7 +3,7 @@ name: "\U0001F41E Bug report"
about: Create a report to help us improve about: Create a report to help us improve
title: "Your title here" title: "Your title here"
labels: ['bug', 'unconfirmed'] labels: ['bug', 'unconfirmed']
assignees: AndriichnekoDm assignees: Ultrazombie
--- ---

2
.github/ISSUE_TEMPLATE/feature_request.md

@ -3,7 +3,7 @@ name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
title: "Your title here" title: "Your title here"
labels: ['feature'] labels: ['feature']
assignees: 'AndriichnekoDm' assignees: 'Ultrazombie'
--- ---

2
.github/ISSUE_TEMPLATE/question.md

@ -3,7 +3,7 @@ name: Question
about: Describe your questions in detail about: Describe your questions in detail
title: "Your title here" title: "Your title here"
labels: ['question'] labels: ['question']
assignees: 'AndriichnekoDm' assignees: 'Ultrazombie'
--- ---

111
application/src/main/data/json/demo/dashboards/rule_engine_statistics.json

@ -13,6 +13,7 @@
"datasources": [ "datasources": [
{ {
"type": "entity", "type": "entity",
"entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018",
"dataKeys": [ "dataKeys": [
{ {
"name": "ruleEngineException", "name": "ruleEngineException",
@ -51,7 +52,59 @@
"_hash": 0.7255162989552142 "_hash": 0.7255162989552142
} }
], ],
"entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018" "alarmFilterConfig": {
"statusList": [
"ACTIVE"
]
},
"latestDataKeys": [
{
"name": "queueName",
"type": "entityField",
"label": "Queue name",
"color": "#ffc107",
"settings": {
"show": false,
"order": null,
"useCellStyleFunction": false,
"cellStyleFunction": "",
"useCellContentFunction": false,
"cellContentFunction": "",
"defaultColumnVisibility": "visible",
"columnSelectionToDisplay": "enabled"
},
"_hash": 0.8104572478982748,
"aggregationType": null,
"units": null,
"decimals": null,
"funcBody": null,
"usePostProcessing": null,
"postFuncBody": null
},
{
"name": "serviceId",
"type": "entityField",
"label": "Service Id",
"color": "#607d8b",
"settings": {
"show": false,
"order": null,
"useCellStyleFunction": false,
"cellStyleFunction": "",
"useCellContentFunction": false,
"cellContentFunction": "",
"defaultColumnVisibility": "visible",
"columnSelectionToDisplay": "enabled"
},
"_hash": 0.38329217099945034,
"aggregationType": null,
"units": null,
"decimals": null,
"funcBody": null,
"usePostProcessing": null,
"postFuncBody": null
}
]
} }
], ],
"timewindow": { "timewindow": {
@ -71,7 +124,9 @@
"settings": { "settings": {
"showTimestamp": true, "showTimestamp": true,
"displayPagination": true, "displayPagination": true,
"defaultPageSize": 10 "defaultPageSize": 10,
"enableSearch": true,
"enableSelectColumnDisplay": true
}, },
"title": "Exceptions", "title": "Exceptions",
"dropShadow": true, "dropShadow": true,
@ -89,7 +144,10 @@
"iconColor": "rgba(0, 0, 0, 0.87)", "iconColor": "rgba(0, 0, 0, 0.87)",
"iconSize": "24px", "iconSize": "24px",
"titleTooltip": "", "titleTooltip": "",
"displayTimewindow": true "displayTimewindow": true,
"configMode": "basic",
"titleFont": null,
"titleColor": null
}, },
"id": "5eb79712-5c24-3060-7e4f-6af36b8f842d", "id": "5eb79712-5c24-3060-7e4f-6af36b8f842d",
"typeFullFqn": "system.cards.timeseries_table" "typeFullFqn": "system.cards.timeseries_table"
@ -329,7 +387,25 @@
"statusList": [ "statusList": [
"ACTIVE" "ACTIVE"
] ]
} },
"latestDataKeys": [
{
"name": "queueName",
"type": "entityField",
"label": "Queue name",
"color": "#ffc107",
"settings": {},
"_hash": 0.8012481564934415
},
{
"name": "serviceId",
"type": "entityField",
"label": "Service Id",
"color": "#607d8b",
"settings": {},
"_hash": 0.0724871638610094
}
]
} }
], ],
"timewindow": { "timewindow": {
@ -724,7 +800,25 @@
"statusList": [ "statusList": [
"ACTIVE" "ACTIVE"
] ]
} },
"latestDataKeys": [
{
"name": "queueName",
"type": "entityField",
"label": "Queue name",
"color": "#f44336",
"settings": {},
"_hash": 0.7242351292118758
},
{
"name": "serviceId",
"type": "entityField",
"label": "Service Id",
"color": "#ffc107",
"settings": {},
"_hash": 0.3347262075244206
}
]
} }
], ],
"timewindow": { "timewindow": {
@ -1004,12 +1098,9 @@
"id": "140f23dd-e3a0-ed98-6189-03c49d2d8018", "id": "140f23dd-e3a0-ed98-6189-03c49d2d8018",
"alias": "TbServiceQueues", "alias": "TbServiceQueues",
"filter": { "filter": {
"type": "assetType", "type": "entityType",
"resolveMultiple": true, "resolveMultiple": true,
"assetNameFilter": "", "entityType": "QUEUE_STATS"
"assetTypes": [
"TbServiceQueue"
]
} }
} }
}, },

32
application/src/main/data/upgrade/3.6.3/schema_update.sql

@ -14,7 +14,6 @@
-- limitations under the License. -- limitations under the License.
-- --
-- create new attribute_kv table schema -- create new attribute_kv table schema
DO DO
$$ $$
@ -105,4 +104,33 @@ EXCEPTION
ROLLBACK; ROLLBACK;
RAISE EXCEPTION 'Error during COPY: %', SQLERRM; RAISE EXCEPTION 'Error during COPY: %', SQLERRM;
END END
$$; $$;
-- OAUTH2 PARAMS ALTER TABLE START
ALTER TABLE oauth2_params
ADD COLUMN IF NOT EXISTS edge_enabled boolean DEFAULT false;
-- OAUTH2 PARAMS ALTER TABLE END
-- QUEUE STATS UPDATE START
CREATE TABLE IF NOT EXISTS queue_stats (
id uuid NOT NULL CONSTRAINT queue_stats_pkey PRIMARY KEY,
created_time bigint NOT NULL,
tenant_id uuid NOT NULL,
queue_name varchar(255) NOT NULL,
service_id varchar(255) NOT NULL,
CONSTRAINT queue_stats_name_unq_key UNIQUE (tenant_id, queue_name, service_id)
);
INSERT INTO queue_stats
SELECT id, created_time, tenant_id, substring(name FROM 1 FOR position('_' IN name) - 1) AS queue_name,
substring(name FROM position('_' IN name) + 1) AS service_id
FROM asset
WHERE type = 'TbServiceQueue' and name LIKE '%\_%';
DELETE FROM asset WHERE type='TbServiceQueue';
DELETE FROM asset_profile WHERE name ='TbServiceQueue';
-- QUEUE STATS UPDATE END

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

@ -79,6 +79,7 @@ import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService; import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.queue.QueueStatsService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
@ -447,6 +448,11 @@ public class ActorSystemContext {
@Getter @Getter
private QueueService queueService; private QueueService queueService;
@Lazy
@Autowired(required = false)
@Getter
private QueueStatsService queueStatsService;
@Lazy @Lazy
@Autowired(required = false) @Autowired(required = false)
@Getter @Getter

3
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
@ -68,7 +69,6 @@ import org.thingsboard.server.common.msg.rule.engine.DeviceEdgeUpdateMsg;
import org.thingsboard.server.common.msg.rule.engine.DeviceNameOrTypeUpdateMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
import org.thingsboard.server.common.util.KvProtoUtil; import org.thingsboard.server.common.util.KvProtoUtil;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry;
@ -97,7 +97,6 @@ import org.thingsboard.server.service.rpc.RpcSubmitStrategy;
import org.thingsboard.server.service.state.DefaultDeviceStateService; import org.thingsboard.server.service.state.DefaultDeviceStateService;
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
import jakarta.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;

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

@ -96,6 +96,7 @@ import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService; import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.queue.QueueStatsService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
@ -768,6 +769,11 @@ class DefaultTbContext implements TbContext {
return mainCtx.getQueueService(); return mainCtx.getQueueService();
} }
@Override
public QueueStatsService getQueueStatsService() {
return mainCtx.getQueueStatsService();
}
@Override @Override
public EventLoopGroup getSharedEventLoop() { public EventLoopGroup getSharedEventLoop() {
return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup();

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

@ -506,7 +506,7 @@ public abstract class BaseController {
TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation) throws ThingsboardException { TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation) throws ThingsboardException {
try { try {
validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId); validateId(tenantProfileId, id -> "Incorrect tenantProfileId " + id);
TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId); TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId);
checkNotNull(tenantProfile, "Tenant profile with id [" + tenantProfileId + "] is not found"); checkNotNull(tenantProfile, "Tenant profile with id [" + tenantProfileId + "] is not found");
accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation); accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation);
@ -541,7 +541,7 @@ public abstract class BaseController {
if (entityId == null) { if (entityId == null) {
throw new ThingsboardException("Parameter entityId can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); throw new ThingsboardException("Parameter entityId can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} }
validateId(entityId.getId(), "Incorrect entityId " + entityId); validateId(entityId.getId(), id -> "Incorrect entityId " + id);
switch (entityId.getEntityType()) { switch (entityId.getEntityType()) {
case ALARM: case ALARM:
checkAlarmId(new AlarmId(entityId.getId()), operation); checkAlarmId(new AlarmId(entityId.getId()), operation);
@ -668,7 +668,7 @@ public abstract class BaseController {
AlarmComment checkAlarmCommentId(AlarmCommentId alarmCommentId, AlarmId alarmId) throws ThingsboardException { AlarmComment checkAlarmCommentId(AlarmCommentId alarmCommentId, AlarmId alarmId) throws ThingsboardException {
try { try {
validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); validateId(alarmCommentId, id -> "Incorrect alarmCommentId " + id);
AlarmComment alarmComment = alarmCommentService.findAlarmCommentByIdAsync(getCurrentUser().getTenantId(), alarmCommentId).get(); AlarmComment alarmComment = alarmCommentService.findAlarmCommentByIdAsync(getCurrentUser().getTenantId(), alarmCommentId).get();
checkNotNull(alarmComment, "Alarm comment with id [" + alarmCommentId + "] is not found"); checkNotNull(alarmComment, "Alarm comment with id [" + alarmCommentId + "] is not found");
if (!alarmId.equals(alarmComment.getAlarmId())) { if (!alarmId.equals(alarmComment.getAlarmId())) {
@ -736,7 +736,7 @@ public abstract class BaseController {
} }
protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException { protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException {
validateId(ruleNodeId, "Incorrect ruleNodeId " + ruleNodeId); validateId(ruleNodeId, id -> "Incorrect ruleNodeId " + id);
RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId); RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId);
checkNotNull(ruleNode, "Rule node with id [" + ruleNodeId + "] is not found"); checkNotNull(ruleNode, "Rule node with id [" + ruleNodeId + "] is not found");
checkRuleChain(ruleNode.getRuleChainId(), operation); checkRuleChain(ruleNode.getRuleChainId(), operation);

1
application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java

@ -20,7 +20,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
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.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;

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

@ -42,6 +42,7 @@ import org.thingsboard.server.service.edge.rpc.processor.device.DeviceEdgeProces
import org.thingsboard.server.service.edge.rpc.processor.device.profile.DeviceProfileEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.device.profile.DeviceProfileEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.edge.EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.edge.EdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.oauth2.OAuth2EdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor;
@ -126,6 +127,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
@Autowired @Autowired
private ResourceEdgeProcessor resourceEdgeProcessor; private ResourceEdgeProcessor resourceEdgeProcessor;
@Autowired
private OAuth2EdgeProcessor oAuth2EdgeProcessor;
@Autowired @Autowired
protected ApplicationEventPublisher eventPublisher; protected ApplicationEventPublisher eventPublisher;
@ -231,6 +235,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case TB_RESOURCE: case TB_RESOURCE:
resourceEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); resourceEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break; break;
case OAUTH2:
oAuth2EdgeProcessor.processOAuth2Notification(tenantId, edgeNotificationMsg);
break;
default: default:
log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type);
} }

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

@ -32,6 +32,7 @@ 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.oauth2.OAuth2Service;
import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.resource.ResourceService;
@ -61,6 +62,7 @@ import org.thingsboard.server.service.edge.rpc.processor.device.profile.DevicePr
import org.thingsboard.server.service.edge.rpc.processor.edge.EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.edge.EdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.oauth2.OAuth2EdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor;
@ -151,6 +153,9 @@ public class EdgeContextComponent {
@Autowired @Autowired
private ResourceService resourceService; private ResourceService resourceService;
@Autowired
private OAuth2Service oAuth2Service;
@Autowired @Autowired
private RateLimitService rateLimitService; private RateLimitService rateLimitService;
@ -220,6 +225,9 @@ public class EdgeContextComponent {
@Autowired @Autowired
private ResourceEdgeProcessor resourceEdgeProcessor; private ResourceEdgeProcessor resourceEdgeProcessor;
@Autowired
private OAuth2EdgeProcessor oAuth2EdgeProcessor;
@Autowired @Autowired
private EdgeMsgConstructor edgeMsgConstructor; private EdgeMsgConstructor edgeMsgConstructor;

75
application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java

@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
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;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
@ -159,43 +160,41 @@ public class EdgeEventSourcingListener {
private boolean isValidSaveEntityEventForEdgeProcessing(SaveEntityEvent<?> event) { private boolean isValidSaveEntityEventForEdgeProcessing(SaveEntityEvent<?> event) {
Object entity = event.getEntity(); Object entity = event.getEntity();
Object oldEntity = event.getOldEntity(); Object oldEntity = event.getOldEntity();
switch (event.getEntityId().getEntityType()) { if (event.getEntityId() != null) {
case RULE_CHAIN: switch (event.getEntityId().getEntityType()) {
if (entity instanceof RuleChain) { case RULE_CHAIN:
RuleChain ruleChain = (RuleChain) entity; if (entity instanceof RuleChain ruleChain) {
return RuleChainType.EDGE.equals(ruleChain.getType()); return RuleChainType.EDGE.equals(ruleChain.getType());
} }
break; break;
case USER: case USER:
if (entity instanceof User) { if (entity instanceof User user) {
User user = (User) entity; if (Authority.SYS_ADMIN.equals(user.getAuthority())) {
if (Authority.SYS_ADMIN.equals(user.getAuthority())) { return false;
return false; }
if (oldEntity != null) {
User oldUser = (User) oldEntity;
cleanUpUserAdditionalInfo(oldUser);
cleanUpUserAdditionalInfo(user);
return !user.equals(oldUser);
}
} }
if (oldEntity != null) { break;
User oldUser = (User) oldEntity; case OTA_PACKAGE:
cleanUpUserAdditionalInfo(oldUser); if (entity instanceof OtaPackageInfo otaPackageInfo) {
cleanUpUserAdditionalInfo(user); return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData();
return !user.equals(oldUser); }
break;
case ALARM:
if (entity instanceof AlarmApiCallResult || entity instanceof Alarm) {
return false;
} }
} break;
break; case TENANT:
case OTA_PACKAGE: return !event.getCreated();
if (entity instanceof OtaPackageInfo) { case API_USAGE_STATE, EDGE:
OtaPackageInfo otaPackageInfo = (OtaPackageInfo) entity;
return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData();
}
break;
case ALARM:
if (entity instanceof AlarmApiCallResult || entity instanceof Alarm) {
return false; return false;
} }
break;
case TENANT:
return !event.getCreated();
case API_USAGE_STATE:
case EDGE:
return false;
} }
// Default: If the entity doesn't match any of the conditions, consider it as valid. // Default: If the entity doesn't match any of the conditions, consider it as valid.
return true; return true;
@ -206,8 +205,7 @@ public class EdgeEventSourcingListener {
if (user.getAdditionalInfo() instanceof NullNode) { if (user.getAdditionalInfo() instanceof NullNode) {
user.setAdditionalInfo(null); user.setAdditionalInfo(null);
} }
if (user.getAdditionalInfo() instanceof ObjectNode) { if (user.getAdditionalInfo() instanceof ObjectNode additionalInfo) {
ObjectNode additionalInfo = ((ObjectNode) user.getAdditionalInfo());
additionalInfo.remove(UserServiceImpl.FAILED_LOGIN_ATTEMPTS); additionalInfo.remove(UserServiceImpl.FAILED_LOGIN_ATTEMPTS);
additionalInfo.remove(UserServiceImpl.LAST_LOGIN_TS); additionalInfo.remove(UserServiceImpl.LAST_LOGIN_TS);
if (additionalInfo.isEmpty()) { if (additionalInfo.isEmpty()) {
@ -221,6 +219,8 @@ public class EdgeEventSourcingListener {
private EdgeEventType getEdgeEventTypeForEntityEvent(Object entity) { private EdgeEventType getEdgeEventTypeForEntityEvent(Object entity) {
if (entity instanceof AlarmComment) { if (entity instanceof AlarmComment) {
return EdgeEventType.ALARM_COMMENT; return EdgeEventType.ALARM_COMMENT;
} else if (entity instanceof OAuth2Info) {
return EdgeEventType.OAUTH2;
} }
return null; return null;
} }
@ -228,6 +228,8 @@ public class EdgeEventSourcingListener {
private String getBodyMsgForEntityEvent(Object entity) { private String getBodyMsgForEntityEvent(Object entity) {
if (entity instanceof AlarmComment) { if (entity instanceof AlarmComment) {
return JacksonUtil.toString(entity); return JacksonUtil.toString(entity);
} else if (entity instanceof OAuth2Info) {
return JacksonUtil.toString(entity);
} }
return null; return null;
} }
@ -238,4 +240,5 @@ public class EdgeEventSourcingListener {
} }
return isCreated ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED; return isCreated ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED;
} }
} }

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

@ -498,9 +498,9 @@ public final class EdgeGrpcSession implements Closeable {
log.trace("[{}][{}][{}] downlink msg(s) are going to be send.", this.tenantId, this.sessionId, copy.size()); log.trace("[{}][{}][{}] downlink msg(s) are going to be send.", this.tenantId, this.sessionId, copy.size());
for (DownlinkMsg downlinkMsg : copy) { for (DownlinkMsg downlinkMsg : copy) {
if (this.clientMaxInboundMessageSize != 0 && downlinkMsg.getSerializedSize() > this.clientMaxInboundMessageSize) { if (this.clientMaxInboundMessageSize != 0 && downlinkMsg.getSerializedSize() > this.clientMaxInboundMessageSize) {
String error = String.format("Client max inbound message size [{%s}] is exceeded. Please increase value of CLOUD_RPC_MAX_INBOUND_MESSAGE_SIZE " + String error = String.format("Client max inbound message size %s is exceeded. Please increase value of CLOUD_RPC_MAX_INBOUND_MESSAGE_SIZE " +
"env variable on the edge and restart it.", this.clientMaxInboundMessageSize); "env variable on the edge and restart it.", this.clientMaxInboundMessageSize);
String message = String.format("Downlink msg size [{%s}] exceeds client max inbound message size [{%s}]. " + String message = String.format("Downlink msg size %s exceeds client max inbound message size %s. " +
"Please increase value of CLOUD_RPC_MAX_INBOUND_MESSAGE_SIZE env variable on the edge and restart it.", downlinkMsg.getSerializedSize(), this.clientMaxInboundMessageSize); "Please increase value of CLOUD_RPC_MAX_INBOUND_MESSAGE_SIZE env variable on the edge and restart it.", downlinkMsg.getSerializedSize(), this.clientMaxInboundMessageSize);
log.error("[{}][{}][{}] {} Message {}", this.tenantId, edge.getId(), this.sessionId, message, downlinkMsg); log.error("[{}][{}][{}] {} Message {}", this.tenantId, edge.getId(), this.sessionId, message, downlinkMsg);
ctx.getNotificationRuleProcessor().process(EdgeCommunicationFailureTrigger.builder().tenantId(tenantId) ctx.getNotificationRuleProcessor().process(EdgeCommunicationFailureTrigger.builder().tenantId(tenantId)
@ -551,35 +551,14 @@ public final class EdgeGrpcSession implements Closeable {
DownlinkMsg downlinkMsg = null; DownlinkMsg downlinkMsg = null;
try { try {
switch (edgeEvent.getAction()) { switch (edgeEvent.getAction()) {
case UPDATED: case UPDATED, ADDED, DELETED, ASSIGNED_TO_EDGE, UNASSIGNED_FROM_EDGE, ALARM_ACK, ALARM_CLEAR, ALARM_DELETE, CREDENTIALS_UPDATED, RELATION_ADD_OR_UPDATE, RELATION_DELETED, CREDENTIALS_REQUEST, RPC_CALL, ASSIGNED_TO_CUSTOMER, UNASSIGNED_FROM_CUSTOMER, ADDED_COMMENT, UPDATED_COMMENT, DELETED_COMMENT -> {
case ADDED:
case DELETED:
case ASSIGNED_TO_EDGE:
case UNASSIGNED_FROM_EDGE:
case ALARM_ACK:
case ALARM_CLEAR:
case ALARM_DELETE:
case CREDENTIALS_UPDATED:
case RELATION_ADD_OR_UPDATE:
case RELATION_DELETED:
case CREDENTIALS_REQUEST:
case RPC_CALL:
case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER:
case ADDED_COMMENT:
case UPDATED_COMMENT:
case DELETED_COMMENT:
downlinkMsg = convertEntityEventToDownlink(edgeEvent); downlinkMsg = convertEntityEventToDownlink(edgeEvent);
log.trace("[{}][{}] entity message processed [{}]", this.tenantId, this.sessionId, downlinkMsg); log.trace("[{}][{}] entity message processed [{}]", this.tenantId, this.sessionId, downlinkMsg);
break; }
case ATTRIBUTES_UPDATED: case ATTRIBUTES_UPDATED, POST_ATTRIBUTES, ATTRIBUTES_DELETED, TIMESERIES_UPDATED ->
case POST_ATTRIBUTES: downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edge, edgeEvent);
case ATTRIBUTES_DELETED: default ->
case TIMESERIES_UPDATED: log.warn("[{}][{}] Unsupported action type [{}]", this.tenantId, this.sessionId, edgeEvent.getAction());
downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent);
break;
default:
log.warn("[{}][{}] Unsupported action type [{}]", this.tenantId, this.sessionId, edgeEvent.getAction());
} }
} catch (Exception e) { } catch (Exception e) {
log.error("[{}][{}] Exception during converting edge event to downlink msg", this.tenantId, this.sessionId, e); log.error("[{}][{}] Exception during converting edge event to downlink msg", this.tenantId, this.sessionId, e);
@ -705,6 +684,8 @@ public final class EdgeGrpcSession implements Closeable {
return ctx.getTenantEdgeProcessor().convertTenantEventToDownlink(edgeEvent, this.edgeVersion); return ctx.getTenantEdgeProcessor().convertTenantEventToDownlink(edgeEvent, this.edgeVersion);
case TENANT_PROFILE: case TENANT_PROFILE:
return ctx.getTenantProfileEdgeProcessor().convertTenantProfileEventToDownlink(edgeEvent, this.edgeVersion); return ctx.getTenantProfileEdgeProcessor().convertTenantProfileEventToDownlink(edgeEvent, this.edgeVersion);
case OAUTH2:
return ctx.getOAuth2EdgeProcessor().convertOAuth2EventToDownlink(edgeEvent);
default: default:
log.warn("[{}] Unsupported edge event type [{}]", this.tenantId, edgeEvent); log.warn("[{}] Unsupported edge event type [{}]", this.tenantId, edgeEvent);
return null; return null;
@ -855,7 +836,7 @@ public final class EdgeGrpcSession implements Closeable {
.build(); .build();
} }
String error = "Failed to validate the edge!"; String error = "Failed to validate the edge!";
String failureMsg = String.format("{%s} Provided request secret: %s", error, request.getEdgeSecret()); String failureMsg = String.format("%s Provided request secret: %s", error, request.getEdgeSecret());
ctx.getNotificationRuleProcessor().process(EdgeCommunicationFailureTrigger.builder().tenantId(tenantId).edgeId(edge.getId()) ctx.getNotificationRuleProcessor().process(EdgeCommunicationFailureTrigger.builder().tenantId(tenantId).edgeId(edge.getId())
.customerId(edge.getCustomerId()).edgeName(edge.getName()).failureMsg(failureMsg).error(error).build()); .customerId(edge.getCustomerId()).edgeName(edge.getName()).failureMsg(failureMsg).error(error).build());
return ConnectResponseMsg.newBuilder() return ConnectResponseMsg.newBuilder()

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

@ -30,6 +30,7 @@ import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetc
import org.thingsboard.server.service.edge.rpc.fetch.DevicesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.DevicesEdgeEventFetcher;
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.EntityViewsEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.EntityViewsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.OAuth2EdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.OtaPackagesEdgeEventFetcher; 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.QueuesEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.RuleChainsEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.RuleChainsEdgeEventFetcher;
@ -79,6 +80,7 @@ public class EdgeSyncCursor {
fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService()));
fetchers.add(new OtaPackagesEdgeEventFetcher(ctx.getOtaPackageService())); fetchers.add(new OtaPackagesEdgeEventFetcher(ctx.getOtaPackageService()));
fetchers.add(new TenantResourcesEdgeEventFetcher(ctx.getResourceService())); fetchers.add(new TenantResourcesEdgeEventFetcher(ctx.getResourceService()));
fetchers.add(new OAuth2EdgeEventFetcher(ctx.getOAuth2Service()));
} }
} }

32
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/oauth2/OAuth2MsgConstructor.java

@ -0,0 +1,32 @@
/**
* Copyright © 2016-2024 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.oauth2;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
@Component
@TbCoreComponent
public class OAuth2MsgConstructor {
public OAuth2UpdateMsg constructOAuth2UpdateMsg(OAuth2Info oAuth2Info) {
return OAuth2UpdateMsg.newBuilder().setEntity(JacksonUtil.toString(oAuth2Info)).build();
}
}

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

@ -46,7 +46,7 @@ public class CustomerEdgeEventFetcher implements EdgeEventFetcher {
List<EdgeEvent> result = new ArrayList<>(); List<EdgeEvent> result = new ArrayList<>();
result.add(EdgeUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(), result.add(EdgeUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(),
EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null)); EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null));
// @voba - returns PageData object to be in sync with other fetchers // returns PageData object to be in sync with other fetchers
return new PageData<>(result, 1, result.size(), false); return new PageData<>(result, 1, result.size(), false);
} }
} }

56
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java

@ -0,0 +1,56 @@
/**
* Copyright © 2016-2024 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.common.util.JacksonUtil;
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.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import java.util.ArrayList;
import java.util.List;
@AllArgsConstructor
@Slf4j
public class OAuth2EdgeEventFetcher implements EdgeEventFetcher {
private final OAuth2Service oAuth2Service;
@Override
public PageLink getPageLink(int pageSize) {
return null;
}
@Override
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) {
List<EdgeEvent> result = new ArrayList<>();
OAuth2Info oAuth2Info = oAuth2Service.findOAuth2Info();
result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.OAUTH2,
EdgeEventActionType.ADDED, null, JacksonUtil.valueToTree(oAuth2Info)));
// returns PageData object to be in sync with other fetchers
return new PageData<>(result, 1, result.size(), false);
}
}

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

@ -25,7 +25,6 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.AttributeScope;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EdgeUtils;
@ -51,9 +50,8 @@ 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.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.page.PageDataIterableByTenantIdEntityId; import org.thingsboard.server.common.data.page.PageDataIterableByTenantIdEntityId;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
@ -75,6 +73,7 @@ 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.edge.EdgeSynchronizationManager; import org.thingsboard.server.dao.edge.EdgeSynchronizationManager;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
@ -93,7 +92,6 @@ import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.TbQueueMsgMetadata;
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.service.entitiy.TbLogEntityActionService;
import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.asset.AssetMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.asset.AssetMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.customer.CustomerMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.customer.CustomerMsgConstructorFactory;
@ -101,6 +99,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.dashboard.DashboardMs
import org.thingsboard.server.service.edge.rpc.constructor.device.DeviceMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.device.DeviceMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.oauth2.OAuth2MsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.queue.QueueMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.queue.QueueMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.relation.RelationMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.relation.RelationMsgConstructorFactory;
@ -114,6 +113,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.widget.WidgetMsgConst
import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.asset.AssetEdgeProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.asset.AssetEdgeProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory;
import org.thingsboard.server.service.entitiy.TbLogEntityActionService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
@ -226,6 +226,9 @@ public abstract class BaseEdgeProcessor {
@Autowired @Autowired
protected ResourceService resourceService; protected ResourceService resourceService;
@Autowired
protected OAuth2Service oAuth2Service;
@Autowired @Autowired
@Lazy @Lazy
protected TbQueueProducerProvider producerProvider; protected TbQueueProducerProvider producerProvider;
@ -257,6 +260,9 @@ public abstract class BaseEdgeProcessor {
@Autowired @Autowired
protected EntityDataMsgConstructor entityDataMsgConstructor; protected EntityDataMsgConstructor entityDataMsgConstructor;
@Autowired
protected OAuth2MsgConstructor oAuth2MsgConstructor;
@Autowired @Autowired
protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory; protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory;
@ -349,35 +355,15 @@ public abstract class BaseEdgeProcessor {
private boolean doSaveIfEdgeIsOffline(EdgeEventType type, private boolean doSaveIfEdgeIsOffline(EdgeEventType type,
EdgeEventActionType action) { EdgeEventActionType action) {
switch (action) { return switch (action) {
case TIMESERIES_UPDATED: case TIMESERIES_UPDATED, ALARM_ACK, ALARM_CLEAR, ALARM_ASSIGNED, ALARM_UNASSIGNED, CREDENTIALS_REQUEST, ADDED_COMMENT, UPDATED_COMMENT ->
case ALARM_ACK: true;
case ALARM_CLEAR: default -> switch (type) {
case ALARM_ASSIGNED: case ALARM, ALARM_COMMENT, RULE_CHAIN, RULE_CHAIN_METADATA, USER, CUSTOMER, TENANT, TENANT_PROFILE, WIDGETS_BUNDLE, WIDGET_TYPE, ADMIN_SETTINGS, OTA_PACKAGE, QUEUE, RELATION ->
case ALARM_UNASSIGNED: true;
case CREDENTIALS_REQUEST: default -> false;
case ADDED_COMMENT: };
case UPDATED_COMMENT: };
return true;
}
switch (type) {
case ALARM:
case ALARM_COMMENT:
case RULE_CHAIN:
case RULE_CHAIN_METADATA:
case USER:
case CUSTOMER:
case TENANT:
case TENANT_PROFILE:
case WIDGETS_BUNDLE:
case WIDGET_TYPE:
case ADMIN_SETTINGS:
case OTA_PACKAGE:
case QUEUE:
case RELATION:
return true;
}
return false;
} }
private ListenableFuture<Void> doSaveEdgeEvent(TenantId tenantId, EdgeId edgeId, EdgeEventType type, EdgeEventActionType action, EntityId entityId, JsonNode body) { private ListenableFuture<Void> doSaveEdgeEvent(TenantId tenantId, EdgeId edgeId, EdgeEventType type, EdgeEventActionType action, EntityId entityId, JsonNode body) {
@ -392,18 +378,13 @@ public abstract class BaseEdgeProcessor {
protected ListenableFuture<Void> processActionForAllEdges(TenantId tenantId, EdgeEventType type, protected ListenableFuture<Void> processActionForAllEdges(TenantId tenantId, EdgeEventType type,
EdgeEventActionType actionType, EntityId entityId, EdgeEventActionType actionType, EntityId entityId,
EdgeId sourceEdgeId) { JsonNode body, EdgeId sourceEdgeId) {
List<ListenableFuture<Void>> futures = new ArrayList<>(); List<ListenableFuture<Void>> futures = new ArrayList<>();
if (TenantId.SYS_TENANT_ID.equals(tenantId)) { if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageDataIterable<TenantId> tenantIds = new PageDataIterable<>(link -> tenantService.findTenantsIds(link), 1024);
PageData<TenantId> tenantsIds; for (TenantId tenantId1 : tenantIds) {
do { futures.addAll(processActionForAllEdgesByTenantId(tenantId1, type, actionType, entityId, body, sourceEdgeId));
tenantsIds = tenantService.findTenantsIds(pageLink); }
for (TenantId tenantId1 : tenantsIds.getData()) {
futures.addAll(processActionForAllEdgesByTenantId(tenantId1, type, actionType, entityId, null, sourceEdgeId));
}
pageLink = pageLink.nextPageLink();
} while (tenantsIds.hasNext());
} else { } else {
futures = processActionForAllEdgesByTenantId(tenantId, type, actionType, entityId, null, sourceEdgeId); futures = processActionForAllEdgesByTenantId(tenantId, type, actionType, entityId, null, sourceEdgeId);
} }
@ -416,22 +397,13 @@ public abstract class BaseEdgeProcessor {
EntityId entityId, EntityId entityId,
JsonNode body, JsonNode body,
EdgeId sourceEdgeId) { EdgeId sourceEdgeId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Edge> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>(); List<ListenableFuture<Void>> futures = new ArrayList<>();
do { PageDataIterable<Edge> edges = new PageDataIterable<>(link -> edgeService.findEdgesByTenantId(tenantId, link), 1024);
pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); for (Edge edge : edges) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (!edge.getId().equals(sourceEdgeId)) {
for (Edge edge : pageData.getData()) { futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, body));
if (!edge.getId().equals(sourceEdgeId)) {
futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, body));
}
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} }
} while (pageData != null && pageData.hasNext()); }
return futures; return futures;
} }
@ -442,31 +414,17 @@ public abstract class BaseEdgeProcessor {
} }
protected UpdateMsgType getUpdateMsgType(EdgeEventActionType actionType) { protected UpdateMsgType getUpdateMsgType(EdgeEventActionType actionType) {
switch (actionType) { return switch (actionType) {
case UPDATED: case UPDATED, CREDENTIALS_UPDATED, ASSIGNED_TO_CUSTOMER, UNASSIGNED_FROM_CUSTOMER, UPDATED_COMMENT ->
case CREDENTIALS_UPDATED: UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
case ASSIGNED_TO_CUSTOMER: case ADDED, ASSIGNED_TO_EDGE, RELATION_ADD_OR_UPDATE, ADDED_COMMENT ->
case UNASSIGNED_FROM_CUSTOMER: UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE;
case UPDATED_COMMENT: case DELETED, UNASSIGNED_FROM_EDGE, RELATION_DELETED, DELETED_COMMENT, ALARM_DELETE ->
return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE; UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE;
case ADDED: case ALARM_ACK -> UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
case ASSIGNED_TO_EDGE: case ALARM_CLEAR -> UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
case RELATION_ADD_OR_UPDATE: default -> throw new RuntimeException("Unsupported actionType [" + actionType + "]");
case ADDED_COMMENT: };
return UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE;
case DELETED:
case UNASSIGNED_FROM_EDGE:
case RELATION_DELETED:
case DELETED_COMMENT:
case ALARM_DELETE:
return UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE;
case ALARM_ACK:
return UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
case ALARM_CLEAR:
return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
default:
throw new RuntimeException("Unsupported actionType [" + actionType + "]");
}
} }
public ListenableFuture<Void> processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { public ListenableFuture<Void> processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
@ -539,48 +497,33 @@ public abstract class BaseEdgeProcessor {
} }
private ListenableFuture<Void> updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) { private ListenableFuture<Void> updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<RuleChain> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>(); List<ListenableFuture<Void>> futures = new ArrayList<>();
do { PageDataIterable<RuleChain> ruleChains = new PageDataIterable<>(link -> ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, link), 1024);
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); for (RuleChain ruleChain : ruleChains) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { List<RuleChainConnectionInfo> connectionInfos =
for (RuleChain ruleChain : pageData.getData()) { ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections();
if (!ruleChain.getId().equals(processingRuleChainId)) { if (connectionInfos != null && !connectionInfos.isEmpty()) {
List<RuleChainConnectionInfo> connectionInfos = for (RuleChainConnectionInfo connectionInfo : connectionInfos) {
ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections(); if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) {
if (connectionInfos != null && !connectionInfos.isEmpty()) { futures.add(saveEdgeEvent(tenantId,
for (RuleChainConnectionInfo connectionInfo : connectionInfos) { edgeId,
if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) { EdgeEventType.RULE_CHAIN_METADATA,
futures.add(saveEdgeEvent(tenantId, EdgeEventActionType.UPDATED,
edgeId, ruleChain.getId(),
EdgeEventType.RULE_CHAIN_METADATA, null));
EdgeEventActionType.UPDATED,
ruleChain.getId(),
null));
}
}
}
} }
} }
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} }
} while (pageData != null && pageData.hasNext()); }
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
private ListenableFuture<Void> processEntityNotificationForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId, EdgeId sourceEdgeId) { private ListenableFuture<Void> processEntityNotificationForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId, EdgeId sourceEdgeId) {
switch (actionType) { return switch (actionType) {
case ADDED: case ADDED, UPDATED, DELETED, CREDENTIALS_UPDATED -> // used by USER entity
case UPDATED: processActionForAllEdges(tenantId, type, actionType, entityId, null, sourceEdgeId);
case DELETED: default -> Futures.immediateFuture(null);
case CREDENTIALS_UPDATED: // used by USER entity };
return processActionForAllEdges(tenantId, type, actionType, entityId, sourceEdgeId);
default:
return Futures.immediateFuture(null);
}
} }
protected EntityId constructEntityId(String entityTypeStr, long entityIdMSB, long entityIdLSB) { protected EntityId constructEntityId(String entityTypeStr, long entityIdMSB, long entityIdLSB) {
@ -623,26 +566,18 @@ public abstract class BaseEdgeProcessor {
} }
protected boolean isEntityExists(TenantId tenantId, EntityId entityId) { protected boolean isEntityExists(TenantId tenantId, EntityId entityId) {
switch (entityId.getEntityType()) { return switch (entityId.getEntityType()) {
case TENANT: case TENANT -> tenantService.findTenantById(tenantId) != null;
return tenantService.findTenantById(tenantId) != null; case DEVICE -> deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())) != null;
case DEVICE: case ASSET -> assetService.findAssetById(tenantId, new AssetId(entityId.getId())) != null;
return deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())) != null; case ENTITY_VIEW ->
case ASSET: entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())) != null;
return assetService.findAssetById(tenantId, new AssetId(entityId.getId())) != null; case CUSTOMER -> customerService.findCustomerById(tenantId, new CustomerId(entityId.getId())) != null;
case ENTITY_VIEW: case USER -> userService.findUserById(tenantId, new UserId(entityId.getId())) != null;
return entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())) != null; case DASHBOARD -> dashboardService.findDashboardById(tenantId, new DashboardId(entityId.getId())) != null;
case CUSTOMER: case EDGE -> edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId())) != null;
return customerService.findCustomerById(tenantId, new CustomerId(entityId.getId())) != null; default -> false;
case USER: };
return userService.findUserById(tenantId, new UserId(entityId.getId())) != null;
case DASHBOARD:
return dashboardService.findDashboardById(tenantId, new DashboardId(entityId.getId())) != null;
case EDGE:
return edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId())) != null;
default:
return false;
}
} }
protected void createRelationFromEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId) { protected void createRelationFromEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId) {
@ -681,37 +616,25 @@ public abstract class BaseEdgeProcessor {
} }
protected AssetProfile checkIfAssetProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, AssetProfile assetProfile, EdgeVersion edgeVersion) { protected AssetProfile checkIfAssetProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, AssetProfile assetProfile, EdgeVersion edgeVersion) {
switch (edgeVersion) { if (EdgeVersion.V_3_3_0.equals(edgeVersion) || EdgeVersion.V_3_3_3.equals(edgeVersion) || EdgeVersion.V_3_4_0.equals(edgeVersion)) {
case V_3_3_3: if (assetProfile.getDefaultDashboardId() != null && isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultDashboardId(), edgeId)) {
case V_3_3_0: assetProfile.setDefaultDashboardId(null);
case V_3_4_0: }
if (assetProfile.getDefaultDashboardId() != null if (assetProfile.getDefaultEdgeRuleChainId() != null && isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultEdgeRuleChainId(), edgeId)) {
&& isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultDashboardId(), edgeId)) { assetProfile.setDefaultEdgeRuleChainId(null);
assetProfile.setDefaultDashboardId(null); }
}
if (assetProfile.getDefaultEdgeRuleChainId() != null
&& isEntityNotAssignedToEdge(tenantId, assetProfile.getDefaultEdgeRuleChainId(), edgeId)) {
assetProfile.setDefaultEdgeRuleChainId(null);
}
break;
} }
return assetProfile; return assetProfile;
} }
protected DeviceProfile checkIfDeviceProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, DeviceProfile deviceProfile, EdgeVersion edgeVersion) { protected DeviceProfile checkIfDeviceProfileDefaultFieldsAssignedToEdge(TenantId tenantId, EdgeId edgeId, DeviceProfile deviceProfile, EdgeVersion edgeVersion) {
switch (edgeVersion) { if (EdgeVersion.V_3_3_0.equals(edgeVersion) || EdgeVersion.V_3_3_3.equals(edgeVersion) || EdgeVersion.V_3_4_0.equals(edgeVersion)) {
case V_3_3_3: if (deviceProfile.getDefaultDashboardId() != null && isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultDashboardId(), edgeId)) {
case V_3_3_0: deviceProfile.setDefaultDashboardId(null);
case V_3_4_0: }
if (deviceProfile.getDefaultDashboardId() != null if (deviceProfile.getDefaultEdgeRuleChainId() != null && isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultEdgeRuleChainId(), edgeId)) {
&& isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultDashboardId(), edgeId)) { deviceProfile.setDefaultEdgeRuleChainId(null);
deviceProfile.setDefaultDashboardId(null); }
}
if (deviceProfile.getDefaultEdgeRuleChainId() != null
&& isEntityNotAssignedToEdge(tenantId, deviceProfile.getDefaultEdgeRuleChainId(), edgeId)) {
deviceProfile.setDefaultEdgeRuleChainId(null);
}
break;
} }
return deviceProfile; return deviceProfile;
} }
@ -726,4 +649,5 @@ public abstract class BaseEdgeProcessor {
} }
return true; return true;
} }
} }

3
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java

@ -32,7 +32,6 @@ 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.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbMsgType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.asset.BaseAssetService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
@ -115,7 +114,7 @@ public abstract class AssetEdgeProcessor extends BaseAssetProcessor implements A
case ASSIGNED_TO_CUSTOMER: case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER: case UNASSIGNED_FROM_CUSTOMER:
Asset asset = assetService.findAssetById(edgeEvent.getTenantId(), assetId); Asset asset = assetService.findAssetById(edgeEvent.getTenantId(), assetId);
if (asset != null && !BaseAssetService.TB_SERVICE_QUEUE.equals(asset.getType())) { if (asset != null) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction()); UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
AssetUpdateMsg assetUpdateMsg = ((AssetMsgConstructor) AssetUpdateMsg assetUpdateMsg = ((AssetMsgConstructor)
assetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructAssetUpdatedMsg(msgType, asset); assetMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)).constructAssetUpdatedMsg(msgType, asset);

20
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java

@ -29,8 +29,7 @@ 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.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.EdgeVersion;
@ -85,20 +84,11 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor {
CustomerId customerId = new CustomerId(EntityIdFactory.getByEdgeEventTypeAndUuid(type, uuid).getId()); CustomerId customerId = new CustomerId(EntityIdFactory.getByEdgeEventTypeAndUuid(type, uuid).getId());
switch (actionType) { switch (actionType) {
case UPDATED: case UPDATED:
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Edge> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>(); List<ListenableFuture<Void>> futures = new ArrayList<>();
do { PageDataIterable<Edge> edges = new PageDataIterable<>(link -> edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, link), 1024);
pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); for (Edge edge : edges) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null));
for (Edge edge : pageData.getData()) { }
futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
case DELETED: case DELETED:
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));

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

@ -0,0 +1,63 @@
/**
* Copyright © 2016-2024 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.oauth2;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EdgeUtils;
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.oauth2.OAuth2Info;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
@Slf4j
@Component
@TbCoreComponent
public class OAuth2EdgeProcessor extends BaseEdgeProcessor {
public DownlinkMsg convertOAuth2EventToDownlink(EdgeEvent edgeEvent) {
DownlinkMsg downlinkMsg = null;
OAuth2Info oAuth2Info = JacksonUtil.convertValue(edgeEvent.getBody(), OAuth2Info.class);
if (oAuth2Info != null) {
OAuth2UpdateMsg oAuth2UpdateMsg = oAuth2MsgConstructor.constructOAuth2UpdateMsg(oAuth2Info);
downlinkMsg = DownlinkMsg.newBuilder()
.setDownlinkMsgId(EdgeUtils.nextPositiveInt())
.addOAuth2UpdateMsg(oAuth2UpdateMsg)
.build();
}
return downlinkMsg;
}
public ListenableFuture<Void> processOAuth2Notification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
OAuth2Info oAuth2Info = JacksonUtil.fromString(edgeNotificationMsg.getBody(), OAuth2Info.class);
if (oAuth2Info == null) {
return Futures.immediateFuture(null);
}
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
return processActionForAllEdges(tenantId, type, actionType, null, JacksonUtil.toJsonNode(edgeNotificationMsg.getBody()), null);
}
}

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

@ -16,12 +16,18 @@
package org.thingsboard.server.service.edge.rpc.processor.telemetry; package org.thingsboard.server.service.edge.rpc.processor.telemetry;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.notification.rule.trigger.EdgeCommunicationFailureTrigger;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.gen.edge.v1.EntityDataProto; import org.thingsboard.server.gen.edge.v1.EntityDataProto;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -31,18 +37,28 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
@TbCoreComponent @TbCoreComponent
public class TelemetryEdgeProcessor extends BaseTelemetryProcessor { public class TelemetryEdgeProcessor extends BaseTelemetryProcessor {
@Value("${edges.rpc.max_telemetry_message_size:0}")
private int maxTelemetryMessageSize;
@Lazy
@Autowired
private NotificationRuleProcessor notificationRuleProcessor;
@Override @Override
protected String getMsgSourceKey() { protected String getMsgSourceKey() {
return DataConstants.EDGE_MSG_SOURCE; return DataConstants.EDGE_MSG_SOURCE;
} }
public DownlinkMsg convertTelemetryEventToDownlink(EdgeEvent edgeEvent) { public DownlinkMsg convertTelemetryEventToDownlink(Edge edge, EdgeEvent edgeEvent) {
if (edgeEvent.getBody() != null) { if (edgeEvent.getBody() != null) {
String bodyStr = edgeEvent.getBody().toString(); String bodyStr = edgeEvent.getBody().toString();
if (bodyStr.length() > 1000) { if (maxTelemetryMessageSize > 0 && bodyStr.length() > maxTelemetryMessageSize) {
log.debug("[{}][{}][{}] Conversion to a DownlinkMsg telemetry event failed due to a size limit violation. " + String error = "Conversion to a DownlinkMsg telemetry event failed due to a size limit violation.";
"Current size is {}, but the limit is 1000. {}", edgeEvent.getTenantId(), edgeEvent.getEdgeId(), String message = String.format("%s Current size is %s, but the limit is %s", error, bodyStr.length(), maxTelemetryMessageSize);
edgeEvent.getEntityId(), bodyStr.length(), StringUtils.truncate(bodyStr, 100)); log.debug("[{}][{}][{}] {}. {}", edgeEvent.getTenantId(), edgeEvent.getEdgeId(),
edgeEvent.getEntityId(), message, StringUtils.truncate(bodyStr, 100));
notificationRuleProcessor.process(EdgeCommunicationFailureTrigger.builder().tenantId(edgeEvent.getTenantId())
.edgeId(edgeEvent.getEdgeId()).customerId(edge.getCustomerId()).edgeName(edge.getName()).failureMsg(message).error(error).build());
return null; return null;
} }
} }
@ -55,4 +71,5 @@ public class TelemetryEdgeProcessor extends BaseTelemetryProcessor {
.addEntityData(entityDataProto) .addEntityData(entityDataProto)
.build(); .build();
} }
} }

1
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/tenant/TenantEdgeProcessor.java

@ -60,4 +60,5 @@ public class TenantEdgeProcessor extends BaseEdgeProcessor {
} }
return downlinkMsg; return downlinkMsg;
} }
} }

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

@ -25,10 +25,9 @@ import org.springframework.context.annotation.Lazy;
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.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.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.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;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -72,11 +71,11 @@ public abstract class AbstractTbEntityService {
@Lazy @Lazy
private EntitiesVersionControlService vcService; private EntitiesVersionControlService vcService;
protected void removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) { protected void removeAlarmsByOriginatorId(TenantId tenantId, EntityId entityId) {
PageData<AlarmInfo> alarms = PageData<AlarmId> alarms =
alarmService.findAlarms(tenantId, new AlarmQuery(entityId, new TimePageLink(Integer.MAX_VALUE), null, null, null, false)); alarmService.findAlarmIdsByOriginatorId(tenantId, entityId, new TimePageLink(Integer.MAX_VALUE));
alarms.getData().stream().map(AlarmInfo::getId).forEach(alarmId -> alarmService.delAlarm(tenantId, alarmId)); alarms.getData().forEach(alarmId -> alarmService.delAlarm(tenantId, alarmId));
} }
protected <T> T checkNotNull(T reference) throws ThingsboardException { protected <T> T checkNotNull(T reference) throws ThingsboardException {

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

@ -22,10 +22,8 @@ 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.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;
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.ThingsboardErrorCode;
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;
@ -33,30 +31,18 @@ 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.asset.AssetService; 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.profile.TbAssetProfileCache;
import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE;
@Service @Service
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService { public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService {
private final AssetService assetService; private final AssetService assetService;
private final TbAssetProfileCache assetProfileCache;
@Override @Override
public Asset save(Asset asset, User user) throws Exception { 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 {
if (TB_SERVICE_QUEUE.equals(asset.getType())) {
throw new ThingsboardException("Unable to save asset with type " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else if (asset.getAssetProfileId() != null) {
AssetProfile assetProfile = assetProfileCache.get(tenantId, asset.getAssetProfileId());
if (assetProfile != null && TB_SERVICE_QUEUE.equals(assetProfile.getName())) {
throw new ThingsboardException("Unable to save asset with profile " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
autoCommit(user, savedAsset.getId()); autoCommit(user, savedAsset.getId());
logEntityActionService.logEntityAction(tenantId, savedAsset.getId(), savedAsset, asset.getCustomerId(), logEntityActionService.logEntityAction(tenantId, savedAsset.getId(), savedAsset, asset.getCustomerId(),
@ -75,7 +61,7 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
TenantId tenantId = asset.getTenantId(); TenantId tenantId = asset.getTenantId();
AssetId assetId = asset.getId(); AssetId assetId = asset.getId();
try { try {
removeAlarmsByEntityId(tenantId, assetId); removeAlarmsByOriginatorId(tenantId, assetId);
assetService.deleteAsset(tenantId, assetId); assetService.deleteAsset(tenantId, assetId);
logEntityActionService.logEntityAction(tenantId, assetId, asset, asset.getCustomerId(), actionType, user, assetId.toString()); logEntityActionService.logEntityAction(tenantId, assetId, asset, asset.getCustomerId(), actionType, user, assetId.toString());
} catch (Exception e) { } catch (Exception e) {

11
application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java

@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
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.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -30,8 +29,6 @@ import org.thingsboard.server.dao.asset.AssetProfileService;
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 static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE;
@Service @Service
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
@ -45,14 +42,6 @@ public class DefaultTbAssetProfileService extends AbstractTbEntityService implem
ActionType actionType = assetProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED; ActionType actionType = assetProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = assetProfile.getTenantId(); TenantId tenantId = assetProfile.getTenantId();
try { try {
if (TB_SERVICE_QUEUE.equals(assetProfile.getName())) {
throw new ThingsboardException("Unable to save asset profile with name " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
} else if (assetProfile.getId() != null) {
AssetProfile foundAssetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfile.getId());
if (foundAssetProfile != null && TB_SERVICE_QUEUE.equals(foundAssetProfile.getName())) {
throw new ThingsboardException("Updating asset profile with name " + TB_SERVICE_QUEUE + " is prohibited!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
AssetProfile savedAssetProfile = checkNotNull(assetProfileService.saveAssetProfile(assetProfile)); AssetProfile savedAssetProfile = checkNotNull(assetProfileService.saveAssetProfile(assetProfile));
autoCommit(user, savedAssetProfile.getId()); autoCommit(user, savedAssetProfile.getId());
logEntityActionService.logEntityAction(tenantId, savedAssetProfile.getId(), savedAssetProfile, logEntityActionService.logEntityAction(tenantId, savedAssetProfile.getId(), savedAssetProfile,

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

@ -94,7 +94,7 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
TenantId tenantId = device.getTenantId(); TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
try { try {
removeAlarmsByEntityId(tenantId, deviceId); removeAlarmsByOriginatorId(tenantId, deviceId);
deviceService.deleteDevice(tenantId, deviceId); deviceService.deleteDevice(tenantId, deviceId);
logEntityActionService.logEntityAction(tenantId, deviceId, device, device.getCustomerId(), actionType, logEntityActionService.logEntityAction(tenantId, deviceId, device, device.getCustomerId(), actionType,
user, deviceId.toString()); user, deviceId.toString());

8
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java

@ -18,6 +18,8 @@ package org.thingsboard.server.service.queue;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -50,9 +52,9 @@ import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequestActorMsg; import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequestActorMsg;
import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.common.util.KvProtoUtil;
import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.common.util.ProtoUtils;
import org.thingsboard.server.dao.resource.ImageCacheKey; import org.thingsboard.server.dao.resource.ImageCacheKey;
import org.thingsboard.server.common.util.KvProtoUtil;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto;
@ -101,8 +103,6 @@ import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWra
import org.thingsboard.server.service.ws.notification.sub.NotificationRequestUpdate; import org.thingsboard.server.service.ws.notification.sub.NotificationRequestUpdate;
import org.thingsboard.server.service.ws.notification.sub.NotificationUpdate; import org.thingsboard.server.service.ws.notification.sub.NotificationUpdate;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -583,7 +583,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
subscriptionManagerService.onTimeSeriesUpdate( subscriptionManagerService.onTimeSeriesUpdate(
toTenantId(tenantIdMSB, tenantIdLSB), toTenantId(tenantIdMSB, tenantIdLSB),
TbSubscriptionUtils.toEntityId(proto.getEntityType(), proto.getEntityIdMSB(), proto.getEntityIdLSB()), TbSubscriptionUtils.toEntityId(proto.getEntityType(), proto.getEntityIdMSB(), proto.getEntityIdLSB()),
KvProtoUtil.toTsKvEntityList(proto.getDataList()), callback); KvProtoUtil.fromTsKvProtoList(proto.getDataList()), callback);
} else if (msg.hasAttrUpdate()) { } else if (msg.hasAttrUpdate()) {
TbAttributeUpdateProto proto = msg.getAttrUpdate(); TbAttributeUpdateProto proto = msg.getAttrUpdate();
subscriptionManagerService.onAttributesUpdate( subscriptionManagerService.onAttributesUpdate(

4
application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java

@ -95,7 +95,7 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements
@Override @Override
public List<LwM2mObject> findLwM2mObject(TenantId tenantId, String sortOrder, String sortProperty, String[] objectIds) { public List<LwM2mObject> findLwM2mObject(TenantId tenantId, String sortOrder, String sortProperty, String[] objectIds) {
log.trace("Executing findByTenantId [{}]", tenantId); log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL, List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL,
objectIds); objectIds);
return resources.stream() return resources.stream()
@ -107,7 +107,7 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements
@Override @Override
public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) { public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) {
log.trace("Executing findByTenantId [{}]", tenantId); log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink); PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink);
return resourcePageData.getData().stream() return resourcePageData.getData().stream()
.flatMap(s -> Stream.ofNullable(toLwM2mObject(s, false))) .flatMap(s -> Stream.ofNullable(toLwM2mObject(s, false)))

47
application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java

@ -21,15 +21,15 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.QueueStatsId;
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.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.queue.QueueStats;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.queue.QueueStatsService;
import org.thingsboard.server.dao.usagerecord.ApiLimitService; import org.thingsboard.server.dao.usagerecord.ApiLimitService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.util.TbRuleEngineComponent; import org.thingsboard.server.queue.util.TbRuleEngineComponent;
@ -52,7 +52,6 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsService { public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsService {
public static final String TB_SERVICE_QUEUE = "TbServiceQueue";
public static final String RULE_ENGINE_EXCEPTION = "ruleEngineException"; public static final String RULE_ENGINE_EXCEPTION = "ruleEngineException";
public static final FutureCallback<Integer> CALLBACK = new FutureCallback<Integer>() { public static final FutureCallback<Integer> CALLBACK = new FutureCallback<Integer>() {
@Override @Override
@ -68,10 +67,10 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
private final TbServiceInfoProvider serviceInfoProvider; private final TbServiceInfoProvider serviceInfoProvider;
private final TelemetrySubscriptionService tsService; private final TelemetrySubscriptionService tsService;
private final AssetService assetService; private final QueueStatsService queueStatsService;
private final ApiLimitService apiLimitService; private final ApiLimitService apiLimitService;
private final Lock lock = new ReentrantLock(); private final Lock lock = new ReentrantLock();
private final ConcurrentMap<TenantQueueKey, AssetId> tenantQueueAssets = new ConcurrentHashMap<>(); private final ConcurrentMap<TenantQueueKey, QueueStatsId> tenantQueueStats = new ConcurrentHashMap<>();
@Value("${queue.rule-engine.stats.max-error-message-length:4096}") @Value("${queue.rule-engine.stats.max-error-message-length:4096}")
private int maxErrorMessageLength; private int maxErrorMessageLength;
@ -82,7 +81,7 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
ruleEngineStats.getTenantStats().forEach((id, stats) -> { ruleEngineStats.getTenantStats().forEach((id, stats) -> {
try { try {
TenantId tenantId = TenantId.fromUUID(id); TenantId tenantId = TenantId.fromUUID(id);
AssetId serviceAssetId = getServiceAssetId(tenantId, queueName); QueueStatsId queueStatsId = getQueueStatsId(tenantId, queueName);
if (stats.getTotalMsgCounter().get() > 0) { if (stats.getTotalMsgCounter().get() > 0) {
List<TsKvEntry> tsList = stats.getCounters().entrySet().stream() List<TsKvEntry> tsList = stats.getCounters().entrySet().stream()
.map(kv -> new BasicTsKvEntry(ts, new LongDataEntry(kv.getKey(), (long) kv.getValue().get()))) .map(kv -> new BasicTsKvEntry(ts, new LongDataEntry(kv.getKey(), (long) kv.getValue().get())))
@ -90,7 +89,7 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
if (!tsList.isEmpty()) { if (!tsList.isEmpty()) {
long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getQueueStatsTtlDays); long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getQueueStatsTtlDays);
ttl = TimeUnit.DAYS.toSeconds(ttl); ttl = TimeUnit.DAYS.toSeconds(ttl);
tsService.saveAndNotifyInternal(tenantId, serviceAssetId, tsList, ttl, CALLBACK); tsService.saveAndNotifyInternal(tenantId, queueStatsId, tsList, ttl, CALLBACK);
} }
} }
} catch (Exception e) { } catch (Exception e) {
@ -104,7 +103,7 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry(RULE_ENGINE_EXCEPTION, e.toJsonString(maxErrorMessageLength))); TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry(RULE_ENGINE_EXCEPTION, e.toJsonString(maxErrorMessageLength)));
long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getRuleEngineExceptionsTtlDays); long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getRuleEngineExceptionsTtlDays);
ttl = TimeUnit.DAYS.toSeconds(ttl); ttl = TimeUnit.DAYS.toSeconds(ttl);
tsService.saveAndNotifyInternal(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), ttl, CALLBACK); tsService.saveAndNotifyInternal(tenantId, getQueueStatsId(tenantId, queueName), Collections.singletonList(tsKv), ttl, CALLBACK);
} catch (Exception e2) { } catch (Exception e2) {
if (!"Asset is referencing to non-existent tenant!".equalsIgnoreCase(e2.getMessage())) { if (!"Asset is referencing to non-existent tenant!".equalsIgnoreCase(e2.getMessage())) {
log.debug("[{}] Failed to store the statistics", tenantId, e2); log.debug("[{}] Failed to store the statistics", tenantId, e2);
@ -113,30 +112,30 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
}); });
} }
private AssetId getServiceAssetId(TenantId tenantId, String queueName) { private QueueStatsId getQueueStatsId(TenantId tenantId, String queueName) {
TenantQueueKey key = new TenantQueueKey(tenantId, queueName); TenantQueueKey key = new TenantQueueKey(tenantId, queueName);
AssetId assetId = tenantQueueAssets.get(key); QueueStatsId queueStatsId = tenantQueueStats.get(key);
if (assetId == null) { if (queueStatsId == null) {
lock.lock(); lock.lock();
try { try {
assetId = tenantQueueAssets.get(key); queueStatsId = tenantQueueStats.get(key);
if (assetId == null) { if (queueStatsId == null) {
Asset asset = assetService.findAssetByTenantIdAndName(tenantId, queueName + "_" + serviceInfoProvider.getServiceId()); QueueStats queueStats = queueStatsService.findByTenantIdAndNameAndServiceId(tenantId, queueName , serviceInfoProvider.getServiceId());
if (asset == null) { if (queueStats == null) {
asset = new Asset(); queueStats = new QueueStats();
asset.setTenantId(tenantId); queueStats.setTenantId(tenantId);
asset.setName(queueName + "_" + serviceInfoProvider.getServiceId()); queueStats.setQueueName(queueName);
asset.setType(TB_SERVICE_QUEUE); queueStats.setServiceId(serviceInfoProvider.getServiceId());
asset = assetService.saveAsset(asset); queueStats = queueStatsService.save(tenantId, queueStats);
} }
assetId = asset.getId(); queueStatsId = queueStats.getId();
tenantQueueAssets.put(key, assetId); tenantQueueStats.put(key, queueStatsId);
} }
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
return assetId; return queueStatsId;
} }
@Data @Data

149
application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java

@ -23,19 +23,9 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
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.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.kv.DoubleDataEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
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.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto;
import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionMgrMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionMgrMsgProto;
import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmDeleteProto; import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmDeleteProto;
import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbAlarmUpdateProto;
@ -46,29 +36,23 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesDeletePr
import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.service.ws.notification.sub.NotificationRequestUpdate; import org.thingsboard.server.service.ws.notification.sub.NotificationRequestUpdate;
import org.thingsboard.server.service.ws.notification.sub.NotificationUpdate; import org.thingsboard.server.service.ws.notification.sub.NotificationUpdate;
import org.thingsboard.server.service.ws.notification.sub.NotificationsSubscriptionUpdate; import org.thingsboard.server.service.ws.notification.sub.NotificationsSubscriptionUpdate;
import org.thingsboard.server.service.ws.telemetry.sub.AlarmSubscriptionUpdate; import org.thingsboard.server.service.ws.telemetry.sub.AlarmSubscriptionUpdate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.UUID; import java.util.UUID;
public class TbSubscriptionUtils { import static org.thingsboard.server.common.util.KvProtoUtil.fromTsValueProtoList;
import static org.thingsboard.server.common.util.KvProtoUtil.toTsKvProtoBuilder;
private static final DataType[] dataTypeByProtoNumber; import static org.thingsboard.server.common.util.KvProtoUtil.toTsValueProto;
static { public class TbSubscriptionUtils {
int arraySize = Arrays.stream(DataType.values()).mapToInt(DataType::getProtoNumber).max().orElse(0);
dataTypeByProtoNumber = new DataType[arraySize + 1];
Arrays.stream(DataType.values()).forEach(dataType -> dataTypeByProtoNumber[dataType.getProtoNumber()] = dataType);
}
public static ToCoreMsg toSubEventProto(String serviceId, TbEntitySubEvent event) { public static ToCoreMsg toSubEventProto(String serviceId, TbEntitySubEvent event) {
SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder();
@ -189,7 +173,7 @@ public class TbSubscriptionUtils {
builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits());
builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
ts.forEach(v -> builder.addData(toKeyValueProto(v.getTs(), v).build())); ts.forEach(v -> builder.addData(toTsKvProtoBuilder(v.getTs(), v).build()));
SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder();
msgBuilder.setTsUpdate(builder); msgBuilder.setTsUpdate(builder);
return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build();
@ -216,7 +200,7 @@ public class TbSubscriptionUtils {
builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
builder.setScope(scope); builder.setScope(scope);
attributes.forEach(v -> builder.addData(toKeyValueProto(v.getLastUpdateTs(), v).build())); attributes.forEach(v -> builder.addData(toTsKvProtoBuilder(v.getLastUpdateTs(), v).build()));
SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder();
msgBuilder.setAttrUpdate(builder); msgBuilder.setAttrUpdate(builder);
@ -239,121 +223,10 @@ public class TbSubscriptionUtils {
return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build();
} }
private static TsKvProto.Builder toKeyValueProto(long ts, KvEntry attr) {
KeyValueProto.Builder dataBuilder = KeyValueProto.newBuilder();
dataBuilder.setKey(attr.getKey());
dataBuilder.setType(toProto(attr.getDataType()));
switch (attr.getDataType()) {
case BOOLEAN:
attr.getBooleanValue().ifPresent(dataBuilder::setBoolV);
break;
case LONG:
attr.getLongValue().ifPresent(dataBuilder::setLongV);
break;
case DOUBLE:
attr.getDoubleValue().ifPresent(dataBuilder::setDoubleV);
break;
case JSON:
attr.getJsonValue().ifPresent(dataBuilder::setJsonV);
break;
case STRING:
attr.getStrValue().ifPresent(dataBuilder::setStringV);
break;
}
return TsKvProto.newBuilder().setTs(ts).setKv(dataBuilder);
}
private static TransportProtos.TsValueProto toTsValueProto(long ts, KvEntry attr) {
TransportProtos.TsValueProto.Builder dataBuilder = TransportProtos.TsValueProto.newBuilder();
dataBuilder.setTs(ts);
dataBuilder.setType(toProto(attr.getDataType()));
switch (attr.getDataType()) {
case BOOLEAN:
attr.getBooleanValue().ifPresent(dataBuilder::setBoolV);
break;
case LONG:
attr.getLongValue().ifPresent(dataBuilder::setLongV);
break;
case DOUBLE:
attr.getDoubleValue().ifPresent(dataBuilder::setDoubleV);
break;
case JSON:
attr.getJsonValue().ifPresent(dataBuilder::setJsonV);
break;
case STRING:
attr.getStrValue().ifPresent(dataBuilder::setStringV);
break;
}
return dataBuilder.build();
}
public static EntityId toEntityId(String entityType, long entityIdMSB, long entityIdLSB) { public static EntityId toEntityId(String entityType, long entityIdMSB, long entityIdLSB) {
return EntityIdFactory.getByTypeAndUuid(entityType, new UUID(entityIdMSB, entityIdLSB)); return EntityIdFactory.getByTypeAndUuid(entityType, new UUID(entityIdMSB, entityIdLSB));
} }
public static List<TsKvEntry> toTsKvEntityList(List<TsKvProto> dataList) {
List<TsKvEntry> result = new ArrayList<>(dataList.size());
dataList.forEach(proto -> result.add(new BasicTsKvEntry(proto.getTs(), getKvEntry(proto.getKv()))));
return result;
}
public static List<AttributeKvEntry> toAttributeKvList(List<TsKvProto> dataList) {
List<AttributeKvEntry> result = new ArrayList<>(dataList.size());
dataList.forEach(proto -> result.add(new BaseAttributeKvEntry(getKvEntry(proto.getKv()), proto.getTs())));
return result;
}
private static KvEntry getKvEntry(KeyValueProto proto) {
KvEntry entry = null;
switch (fromProto(proto.getType())) {
case BOOLEAN:
entry = new BooleanDataEntry(proto.getKey(), proto.getBoolV());
break;
case LONG:
entry = new LongDataEntry(proto.getKey(), proto.getLongV());
break;
case DOUBLE:
entry = new DoubleDataEntry(proto.getKey(), proto.getDoubleV());
break;
case STRING:
entry = new StringDataEntry(proto.getKey(), proto.getStringV());
break;
case JSON:
entry = new JsonDataEntry(proto.getKey(), proto.getJsonV());
break;
}
return entry;
}
public static List<TsKvEntry> toTsKvEntityList(String key, List<TransportProtos.TsValueProto> dataList) {
List<TsKvEntry> result = new ArrayList<>(dataList.size());
dataList.forEach(proto -> result.add(new BasicTsKvEntry(proto.getTs(), getKvEntry(key, proto))));
return result;
}
private static KvEntry getKvEntry(String key, TransportProtos.TsValueProto proto) {
KvEntry entry = null;
switch (fromProto(proto.getType())) {
case BOOLEAN:
entry = new BooleanDataEntry(key, proto.getBoolV());
break;
case LONG:
entry = new LongDataEntry(key, proto.getLongV());
break;
case DOUBLE:
entry = new DoubleDataEntry(key, proto.getDoubleV());
break;
case STRING:
entry = new StringDataEntry(key, proto.getStringV());
break;
case JSON:
entry = new JsonDataEntry(key, proto.getJsonV());
break;
}
return entry;
}
public static ToCoreMsg toAlarmUpdateProto(TenantId tenantId, EntityId entityId, AlarmInfo alarm) { public static ToCoreMsg toAlarmUpdateProto(TenantId tenantId, EntityId entityId, AlarmInfo alarm) {
TbAlarmUpdateProto.Builder builder = TbAlarmUpdateProto.newBuilder(); TbAlarmUpdateProto.Builder builder = TbAlarmUpdateProto.newBuilder();
builder.setEntityType(entityId.getEntityType().name()); builder.setEntityType(entityId.getEntityType().name());
@ -411,7 +284,7 @@ public class TbSubscriptionUtils {
public static List<TsKvEntry> fromProto(TransportProtos.TbSubUpdateProto proto) { public static List<TsKvEntry> fromProto(TransportProtos.TbSubUpdateProto proto) {
List<TsKvEntry> result = new ArrayList<>(); List<TsKvEntry> result = new ArrayList<>();
for (var p : proto.getDataList()) { for (var p : proto.getDataList()) {
result.addAll(toTsKvEntityList(p.getKey(), p.getTsValueList())); result.addAll(fromTsValueProtoList(p.getKey(), p.getTsValueList()));
} }
return result; return result;
} }
@ -453,12 +326,4 @@ public class TbSubscriptionUtils {
return ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg(result).build(); return ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg(result).build();
} }
public static TransportProtos.KeyValueType toProto(DataType dataType) {
return TransportProtos.KeyValueType.forNumber(dataType.getProtoNumber());
}
public static DataType fromProto(TransportProtos.KeyValueType keyValueType) {
return dataTypeByProtoNumber[keyValueType.getNumber()];
}
} }

6
application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -101,7 +101,11 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
ctx.putInternalId(exportData.getExternalId(), importResult.getSavedEntity().getId()); ctx.putInternalId(exportData.getExternalId(), importResult.getSavedEntity().getId());
ctx.addReferenceCallback(exportData.getExternalId(), importResult.getSaveReferencesCallback()); ctx.addReferenceCallback(exportData.getExternalId(), importResult.getSaveReferencesCallback());
ctx.addEventCallback(importResult.getSendEventsCallback()); if (ctx.isRollbackOnError()) {
ctx.addEventCallback(importResult.getSendEventsCallback());
} else {
importResult.getSendEventsCallback().run();
}
return importResult; return importResult;
} }

76
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings; import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
@ -89,6 +90,7 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Function; import java.util.function.Function;
@ -246,16 +248,18 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
switch (request.getType()) { switch (request.getType()) {
case SINGLE_ENTITY: { case SINGLE_ENTITY: {
SingleEntityVersionLoadRequest versionLoadRequest = (SingleEntityVersionLoadRequest) request; SingleEntityVersionLoadRequest versionLoadRequest = (SingleEntityVersionLoadRequest) request;
ctx.setRollbackOnError(true);
VersionLoadConfig config = versionLoadRequest.getConfig(); VersionLoadConfig config = versionLoadRequest.getConfig();
ListenableFuture<EntityExportData> future = gitServiceQueue.getEntity(user.getTenantId(), request.getVersionId(), versionLoadRequest.getExternalEntityId()); ListenableFuture<EntityExportData> future = gitServiceQueue.getEntity(user.getTenantId(), request.getVersionId(), versionLoadRequest.getExternalEntityId());
DonAsynchron.withCallback(future, DonAsynchron.withCallback(future,
entityData -> doInTemplate(ctx, request, c -> loadSingleEntity(c, config, entityData)), entityData -> load(ctx, request, c -> loadSingleEntity(c, config, entityData)),
e -> processLoadError(ctx, e), executor); e -> processLoadError(ctx, e), executor);
break; break;
} }
case ENTITY_TYPE: { case ENTITY_TYPE: {
EntityTypeVersionLoadRequest versionLoadRequest = (EntityTypeVersionLoadRequest) request; EntityTypeVersionLoadRequest versionLoadRequest = (EntityTypeVersionLoadRequest) request;
executor.submit(() -> doInTemplate(ctx, request, c -> loadMultipleEntities(c, versionLoadRequest))); ctx.setRollbackOnError(versionLoadRequest.isRollbackOnError());
executor.submit(() -> load(ctx, request, c -> loadMultipleEntities(c, versionLoadRequest)));
break; break;
} }
default: default:
@ -265,19 +269,24 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
return ctx.getRequestId(); return ctx.getRequestId();
} }
private <R> VersionLoadResult doInTemplate(EntitiesImportCtx ctx, VersionLoadRequest request, Function<EntitiesImportCtx, VersionLoadResult> function) { private <R> VersionLoadResult load(EntitiesImportCtx ctx, VersionLoadRequest request, Function<EntitiesImportCtx, VersionLoadResult> loadFunction) {
try { try {
VersionLoadResult result = transactionTemplate.execute(status -> { VersionLoadResult result;
try { if (ctx.isRollbackOnError()) {
return function.apply(ctx); result = transactionTemplate.execute(status -> {
} catch (RuntimeException e) { try {
throw e; return loadFunction.apply(ctx);
} catch (Exception e) { } catch (RuntimeException e) {
throw new RuntimeException(e); // to prevent UndeclaredThrowableException throw e;
} catch (Exception e) {
throw new RuntimeException(e); // to prevent UndeclaredThrowableException
}
});
for (ThrowingRunnable eventCallback : ctx.getEventCallbacks()) {
eventCallback.run();
} }
}); } else {
for (ThrowingRunnable throwingRunnable : ctx.getEventCallbacks()) { result = loadFunction.apply(ctx);
throwingRunnable.run();
} }
result.setDone(true); result.setDone(true);
return cachePut(ctx.getRequestId(), result); return cachePut(ctx.getRequestId(), result);
@ -324,7 +333,6 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
sw.startNew("Entities " + entityType.name()); sw.startNew("Entities " + entityType.name());
ctx.setSettings(getEntityImportSettings(request, entityType)); ctx.setSettings(getEntityImportSettings(request, entityType));
importEntities(ctx, entityType); importEntities(ctx, entityType);
persistToCache(ctx);
} }
sw.startNew("Reimport"); sw.startNew("Reimport");
@ -336,7 +344,6 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
.filter(entityType -> request.getEntityTypes().get(entityType).isRemoveOtherEntities()) .filter(entityType -> request.getEntityTypes().get(entityType).isRemoveOtherEntities())
.sorted(exportImportService.getEntityTypeComparatorForImport().reversed()) .sorted(exportImportService.getEntityTypeComparatorForImport().reversed())
.forEach(entityType -> removeOtherEntities(ctx, entityType)); .forEach(entityType -> removeOtherEntities(ctx, entityType));
persistToCache(ctx);
sw.startNew("References and Relations"); sw.startNew("References and Relations");
exportImportService.saveReferencesAndRelations(ctx); exportImportService.saveReferencesAndRelations(ctx);
@ -389,6 +396,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
ctx.getImportedEntities().computeIfAbsent(entityType, t -> new HashSet<>()) ctx.getImportedEntities().computeIfAbsent(entityType, t -> new HashSet<>())
.add(importResult.getSavedEntity().getId()); .add(importResult.getSavedEntity().getId());
} }
persistToCache(ctx);
log.debug("Imported {} pack ({}) for tenant {}", entityType, entityDataList.size(), ctx.getTenantId()); log.debug("Imported {} pack ({}) for tenant {}", entityType, entityDataList.size(), ctx.getTenantId());
offset += limit; offset += limit;
} while (entityDataList.size() == limit); } while (entityDataList.size() == limit);
@ -413,17 +422,34 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
private void removeOtherEntities(EntitiesImportCtx ctx, EntityType entityType) { private void removeOtherEntities(EntitiesImportCtx ctx, EntityType entityType) {
DaoUtil.processInBatches(pageLink -> { var entities = new PageDataIterable<>(link -> exportableEntitiesService.findEntitiesIdsByTenantId(ctx.getTenantId(), entityType, link), 100);
return exportableEntitiesService.findEntitiesByTenantId(ctx.getTenantId(), entityType, pageLink); Set<EntityId> toRemove = new HashSet<>();
}, 100, entity -> { for (EntityId entityId : entities) {
if (ctx.getImportedEntities().get(entityType) == null || !ctx.getImportedEntities().get(entityType).contains(entity.getId())) { if (ctx.getImportedEntities().get(entityType) == null || !ctx.getImportedEntities().get(entityType).contains(entityId)) {
exportableEntitiesService.removeById(ctx.getTenantId(), entity.getId()); toRemove.add(entityId);
ctx.addEventCallback(() -> logEntityActionService.logEntityAction(ctx.getTenantId(), entity.getId(), entity, null,
ActionType.DELETED, ctx.getUser()));
ctx.registerDeleted(entityType);
} }
}); }
for (EntityId entityId : toRemove) {
ExportableEntity<EntityId> entity = exportableEntitiesService.findEntityById(entityId);
exportableEntitiesService.removeById(ctx.getTenantId(), entityId);
ThrowingRunnable callback = () -> {
logEntityActionService.logEntityAction(ctx.getTenantId(), entity.getId(), entity, null,
ActionType.DELETED, ctx.getUser());
};
if (ctx.isRollbackOnError()) {
ctx.addEventCallback(callback);
} else {
try {
callback.run();
} catch (ThingsboardException e) {
throw new RuntimeException(e);
}
}
ctx.registerDeleted(entityType);
}
persistToCache(ctx);
} }
private VersionLoadResult onError(EntityId externalId, Throwable e) { private VersionLoadResult onError(EntityId externalId, Throwable e) {

1
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java

@ -58,6 +58,7 @@ public class EntitiesImportCtx {
private boolean finalImportAttempt = false; private boolean finalImportAttempt = false;
private EntityImportSettings settings; private EntityImportSettings settings;
private EntityImportResult<?> currentImportResult; private EntityImportResult<?> currentImportResult;
private boolean rollbackOnError;
public EntitiesImportCtx(UUID requestId, User user, String versionId) { public EntitiesImportCtx(UUID requestId, User user, String versionId) {
this(requestId, user, versionId, null); this(requestId, user, versionId, null);

4
application/src/main/resources/thingsboard.yml

@ -866,6 +866,8 @@ js:
monitor_thread_pool_size: "${LOCAL_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}" monitor_thread_pool_size: "${LOCAL_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}"
# Maximum CPU time in milliseconds allowed for script execution # Maximum CPU time in milliseconds allowed for script execution
max_cpu_time: "${LOCAL_JS_SANDBOX_MAX_CPU_TIME:8000}" max_cpu_time: "${LOCAL_JS_SANDBOX_MAX_CPU_TIME:8000}"
# Maximum memory in Bytes which JS executor thread can allocate (approximate calculation). A zero memory limit in combination with a non-zero CPU limit is not recommended due to the implementation of Nashorn 0.4.2. 100MiB is effectively unlimited for most cases
max_memory: "${LOCAL_JS_SANDBOX_MAX_MEMORY:104857600}"
# Maximum allowed JavaScript execution errors before JavaScript will be blacklisted # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted
max_errors: "${LOCAL_JS_SANDBOX_MAX_ERRORS:3}" max_errors: "${LOCAL_JS_SANDBOX_MAX_ERRORS:3}"
# JS Eval max request timeout. 0 - no timeout # JS Eval max request timeout. 0 - no timeout
@ -1304,6 +1306,8 @@ edges:
private_key: "${EDGES_RPC_SSL_PRIVATE_KEY:privateKeyFile.pem}" private_key: "${EDGES_RPC_SSL_PRIVATE_KEY:privateKeyFile.pem}"
# Maximum size (in bytes) of inbound messages the cloud can handle from the edge. By default, it can handle messages up to 4 Megabytes # Maximum size (in bytes) of inbound messages the cloud can handle from the edge. By default, it can handle messages up to 4 Megabytes
max_inbound_message_size: "${EDGES_RPC_MAX_INBOUND_MESSAGE_SIZE:4194304}" max_inbound_message_size: "${EDGES_RPC_MAX_INBOUND_MESSAGE_SIZE:4194304}"
# Maximum length of telemetry (time-series and attributes) message the cloud sends to the edge. By default, there is no limitation.
max_telemetry_message_size: "${EDGES_RPC_MAX_TELEMETRY_MESSAGE_SIZE:0}"
storage: storage:
# Max records of edge event to read from DB and sent to the edge # Max records of edge event to read from DB and sent to the edge
max_read_records_count: "${EDGES_STORAGE_MAX_READ_RECORDS_COUNT:50}" max_read_records_count: "${EDGES_STORAGE_MAX_READ_RECORDS_COUNT:50}"

53
application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java

@ -29,6 +29,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
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.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
@ -45,16 +46,17 @@ 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.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.relation.EntityRelation;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.asset.AssetDao; import org.thingsboard.server.dao.asset.AssetDao;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -327,6 +329,53 @@ public class AssetControllerTest extends AbstractControllerTest {
.andExpect(statusReason(containsString(msgErrorNoFound("Alarm", alarm.getId().getId().toString())))); .andExpect(statusReason(containsString(msgErrorNoFound("Alarm", alarm.getId().getId().toString()))));
} }
@Test
public void testDeleteAssetWithPropagatedAlarm() throws Exception {
Device device = new Device();
device.setTenantId(savedTenant.getTenantId());
device.setName("Test device");
device.setLabel("Label");
device.setType("default");
device = doPost("/api/device", device, Device.class);
Asset asset = new Asset();
asset.setName("My asset");
asset.setType("default");
asset = doPost("/api/asset", asset, Asset.class);
EntityRelation entityRelation = new EntityRelation(asset.getId(), device.getId(), "CONTAINS");
doPost("/api/relation", entityRelation);
//create alarm
Alarm alarm = Alarm.builder()
.tenantId(savedTenant.getTenantId())
.originator(device.getId())
.severity(AlarmSeverity.CRITICAL)
.type("test_type")
.propagate(true)
.build();
alarm = doPost("/api/alarm", alarm, Alarm.class);
Assert.assertNotNull(alarm);
PageData<AlarmInfo> deviceAlarms = doGetTyped("/api/alarm/DEVICE/" + device.getUuidId() + "?page=0&pageSize=10", new TypeReference<>() {
});
assertThat(deviceAlarms.getData()).hasSize(1);
PageData<AlarmInfo> assetAlarms = doGetTyped("/api/alarm/ASSET/" + asset.getUuidId() + "?page=0&pageSize=10", new TypeReference<>() {
});
assertThat(assetAlarms.getData()).hasSize(1);
//delete asset
doDelete("/api/asset/" + asset.getId().getId().toString())
.andExpect(status().isOk());
//check device alarms
PageData<AlarmInfo> deviceAlarmsAfterAssetDeletion = doGetTyped("/api/alarm/DEVICE/" + device.getUuidId() + "?page=0&pageSize=10", new TypeReference<PageData<AlarmInfo>>() {
});
assertThat(deviceAlarmsAfterAssetDeletion.getData()).hasSize(1);
}
@Test @Test
public void testDeleteAssetAssignedToEntityView() throws Exception { public void testDeleteAssetAssignedToEntityView() throws Exception {
Asset asset1 = new Asset(); Asset asset1 = new Asset();
@ -567,8 +616,6 @@ public class AssetControllerTest extends AbstractControllerTest {
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, cntEntity, cntEntity, cntEntity); ActionType.ADDED, cntEntity, cntEntity, cntEntity);
loadedAssets.removeIf(asset -> asset.getType().equals(DefaultRuleEngineStatisticsService.TB_SERVICE_QUEUE));
assets.sort(idComparator); assets.sort(idComparator);
loadedAssets.sort(idComparator); loadedAssets.sort(idComparator);

21
application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java

@ -25,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.asset.Asset;
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.TenantId;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
@ -34,12 +33,13 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.queue.ProcessingStrategy; import org.thingsboard.server.common.data.queue.ProcessingStrategy;
import org.thingsboard.server.common.data.queue.ProcessingStrategyType; import org.thingsboard.server.common.data.queue.ProcessingStrategyType;
import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.queue.QueueStats;
import org.thingsboard.server.common.data.queue.SubmitStrategy; import org.thingsboard.server.common.data.queue.SubmitStrategy;
import org.thingsboard.server.common.data.queue.SubmitStrategyType; import org.thingsboard.server.common.data.queue.SubmitStrategyType;
import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.queue.QueueStatsService;
import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.timeseries.TimeseriesDao; import org.thingsboard.server.dao.timeseries.TimeseriesDao;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
@ -50,6 +50,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingRes
import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService; import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService;
import org.thingsboard.server.service.stats.RuleEngineStatisticsService; import org.thingsboard.server.service.stats.RuleEngineStatisticsService;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -66,7 +67,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE;
@DaoSqlTest @DaoSqlTest
@TestPropertySource(properties = { @TestPropertySource(properties = {
@ -81,7 +81,7 @@ public class BaseQueueControllerTest extends AbstractControllerTest {
@SpyBean @SpyBean
private TimeseriesDao timeseriesDao; private TimeseriesDao timeseriesDao;
@Autowired @Autowired
private AssetService assetService; private QueueStatsService queueStatsService;
@Test @Test
public void testQueueWithServiceTypeRE() throws Exception { public void testQueueWithServiceTypeRE() throws Exception {
@ -176,16 +176,17 @@ public class BaseQueueControllerTest extends AbstractControllerTest {
}); });
ruleEngineStatisticsService.reportQueueStats(System.currentTimeMillis(), testStats); ruleEngineStatisticsService.reportQueueStats(System.currentTimeMillis(), testStats);
Asset serviceAsset = assetService.findAssetsByTenantIdAndType(tenantId, TB_SERVICE_QUEUE, new PageLink(100)).getData() List<QueueStats> queueStatsList = queueStatsService.findByTenantId(tenantId);
.stream().filter(asset -> asset.getName().startsWith(queue.getName())) assertThat(queueStatsList).hasSize(1);
.findFirst().get(); QueueStats queueStats = queueStatsList.get(0);
assertThat(queueStats.getQueueName()).isEqualTo(queue.getName());
ArgumentCaptor<Long> ttlCaptor = ArgumentCaptor.forClass(Long.class); ArgumentCaptor<Long> ttlCaptor = ArgumentCaptor.forClass(Long.class);
verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { verify(timeseriesDao).save(eq(tenantId), eq(queueStats.getId()), argThat(tsKvEntry -> {
return tsKvEntry.getKey().equals(TbRuleEngineConsumerStats.SUCCESSFUL_MSGS) && return tsKvEntry.getKey().equals(TbRuleEngineConsumerStats.SUCCESSFUL_MSGS) &&
tsKvEntry.getLongValue().get().equals(5L); tsKvEntry.getLongValue().get().equals(5L);
}), ttlCaptor.capture()); }), ttlCaptor.capture());
verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { verify(timeseriesDao).save(eq(tenantId), eq(queueStats.getId()), argThat(tsKvEntry -> {
return tsKvEntry.getKey().equals(TbRuleEngineConsumerStats.FAILED_MSGS) && return tsKvEntry.getKey().equals(TbRuleEngineConsumerStats.FAILED_MSGS) &&
tsKvEntry.getLongValue().get().equals(5L); tsKvEntry.getLongValue().get().equals(5L);
}), ttlCaptor.capture()); }), ttlCaptor.capture());
@ -193,7 +194,7 @@ public class BaseQueueControllerTest extends AbstractControllerTest {
assertThat(usedTtl).isEqualTo(TimeUnit.DAYS.toSeconds(queueStatsTtlDays)); assertThat(usedTtl).isEqualTo(TimeUnit.DAYS.toSeconds(queueStatsTtlDays));
}); });
verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { verify(timeseriesDao).save(eq(tenantId), eq(queueStats.getId()), argThat(tsKvEntry -> {
return tsKvEntry.getKey().equals(DefaultRuleEngineStatisticsService.RULE_ENGINE_EXCEPTION) && return tsKvEntry.getKey().equals(DefaultRuleEngineStatisticsService.RULE_ENGINE_EXCEPTION) &&
tsKvEntry.getJsonValue().get().equals(ruleEngineException.toJsonString(0)); tsKvEntry.getJsonValue().get().equals(ruleEngineException.toJsonString(0));
}), ttlCaptor.capture()); }), ttlCaptor.capture());

38
application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java

@ -76,6 +76,7 @@ import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg;
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg; import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg;
@ -631,7 +632,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
List<Edge> loadedEdges = new ArrayList<>(); List<Edge> loadedEdges = new ArrayList<>();
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
PageData<Edge> pageData = null; PageData<Edge> pageData;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?",
new TypeReference<>() { new TypeReference<>() {
@ -885,6 +886,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret()); EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret());
edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); edgeImitator.ignoreType(UserCredentialsUpdateMsg.class);
edgeImitator.ignoreType(OAuth2UpdateMsg.class);
edgeImitator.expectMessageAmount(24); edgeImitator.expectMessageAmount(24);
edgeImitator.connect(); edgeImitator.connect();
@ -973,8 +975,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popQueueMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) { private boolean popQueueMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof QueueUpdateMsg) { if (message instanceof QueueUpdateMsg queueUpdateMsg) {
QueueUpdateMsg queueUpdateMsg = (QueueUpdateMsg) message;
Queue queue = JacksonUtil.fromString(queueUpdateMsg.getEntity(), Queue.class, true); Queue queue = JacksonUtil.fromString(queueUpdateMsg.getEntity(), Queue.class, true);
Assert.assertNotNull(queue); Assert.assertNotNull(queue);
if (msgType.equals(queueUpdateMsg.getMsgType()) && name.equals(queue.getName())) { if (msgType.equals(queueUpdateMsg.getMsgType()) && name.equals(queue.getName())) {
@ -988,8 +989,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popRuleChainMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) { private boolean popRuleChainMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof RuleChainUpdateMsg) { if (message instanceof RuleChainUpdateMsg ruleChainUpdateMsg) {
RuleChainUpdateMsg ruleChainUpdateMsg = (RuleChainUpdateMsg) message;
RuleChain ruleChain = JacksonUtil.fromString(ruleChainUpdateMsg.getEntity(), RuleChain.class, true); RuleChain ruleChain = JacksonUtil.fromString(ruleChainUpdateMsg.getEntity(), RuleChain.class, true);
Assert.assertNotNull(ruleChain); Assert.assertNotNull(ruleChain);
if (msgType.equals(ruleChainUpdateMsg.getMsgType()) if (msgType.equals(ruleChainUpdateMsg.getMsgType())
@ -1005,8 +1005,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popAdminSettingsMsg(List<AbstractMessage> messages, String key) { private boolean popAdminSettingsMsg(List<AbstractMessage> messages, String key) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof AdminSettingsUpdateMsg) { if (message instanceof AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
AdminSettingsUpdateMsg adminSettingsUpdateMsg = (AdminSettingsUpdateMsg) message;
AdminSettings adminSettings = JacksonUtil.fromString(adminSettingsUpdateMsg.getEntity(), AdminSettings.class, true); AdminSettings adminSettings = JacksonUtil.fromString(adminSettingsUpdateMsg.getEntity(), AdminSettings.class, true);
Assert.assertNotNull(adminSettings); Assert.assertNotNull(adminSettings);
if (key.equals(adminSettings.getKey())) { if (key.equals(adminSettings.getKey())) {
@ -1020,8 +1019,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popDeviceProfileMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) { private boolean popDeviceProfileMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof DeviceProfileUpdateMsg) { if (message instanceof DeviceProfileUpdateMsg deviceProfileUpdateMsg) {
DeviceProfileUpdateMsg deviceProfileUpdateMsg = (DeviceProfileUpdateMsg) message;
DeviceProfile deviceProfile = JacksonUtil.fromString(deviceProfileUpdateMsg.getEntity(), DeviceProfile.class, true); DeviceProfile deviceProfile = JacksonUtil.fromString(deviceProfileUpdateMsg.getEntity(), DeviceProfile.class, true);
Assert.assertNotNull(deviceProfile); Assert.assertNotNull(deviceProfile);
if (msgType.equals(deviceProfileUpdateMsg.getMsgType()) if (msgType.equals(deviceProfileUpdateMsg.getMsgType())
@ -1036,8 +1034,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popDeviceMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) { private boolean popDeviceMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof DeviceUpdateMsg) { if (message instanceof DeviceUpdateMsg deviceUpdateMsg) {
DeviceUpdateMsg deviceUpdateMsg = (DeviceUpdateMsg) message;
Device device = JacksonUtil.fromString(deviceUpdateMsg.getEntity(), Device.class, true); Device device = JacksonUtil.fromString(deviceUpdateMsg.getEntity(), Device.class, true);
Assert.assertNotNull(device); Assert.assertNotNull(device);
if (msgType.equals(deviceUpdateMsg.getMsgType()) if (msgType.equals(deviceUpdateMsg.getMsgType())
@ -1052,8 +1049,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popAssetProfileMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) { private boolean popAssetProfileMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof AssetProfileUpdateMsg) { if (message instanceof AssetProfileUpdateMsg assetProfileUpdateMsg) {
AssetProfileUpdateMsg assetProfileUpdateMsg = (AssetProfileUpdateMsg) message;
AssetProfile assetProfile = JacksonUtil.fromString(assetProfileUpdateMsg.getEntity(), AssetProfile.class, true); AssetProfile assetProfile = JacksonUtil.fromString(assetProfileUpdateMsg.getEntity(), AssetProfile.class, true);
Assert.assertNotNull(assetProfile); Assert.assertNotNull(assetProfile);
if (msgType.equals(assetProfileUpdateMsg.getMsgType()) if (msgType.equals(assetProfileUpdateMsg.getMsgType())
@ -1068,8 +1064,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popAssetMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) { private boolean popAssetMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String name) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof AssetUpdateMsg) { if (message instanceof AssetUpdateMsg assetUpdateMsg) {
AssetUpdateMsg assetUpdateMsg = (AssetUpdateMsg) message;
Asset asset = JacksonUtil.fromString(assetUpdateMsg.getEntity(), Asset.class, true); Asset asset = JacksonUtil.fromString(assetUpdateMsg.getEntity(), Asset.class, true);
Assert.assertNotNull(asset); Assert.assertNotNull(asset);
if (msgType.equals(assetUpdateMsg.getMsgType()) if (msgType.equals(assetUpdateMsg.getMsgType())
@ -1084,8 +1079,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popUserMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String email, Authority authority) { private boolean popUserMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String email, Authority authority) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof UserUpdateMsg) { if (message instanceof UserUpdateMsg userUpdateMsg) {
UserUpdateMsg userUpdateMsg = (UserUpdateMsg) message;
User user = JacksonUtil.fromString(userUpdateMsg.getEntity(), User.class, true); User user = JacksonUtil.fromString(userUpdateMsg.getEntity(), User.class, true);
Assert.assertNotNull(user); Assert.assertNotNull(user);
if (msgType.equals(userUpdateMsg.getMsgType()) if (msgType.equals(userUpdateMsg.getMsgType())
@ -1101,8 +1095,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popCustomerMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String title) { private boolean popCustomerMsg(List<AbstractMessage> messages, UpdateMsgType msgType, String title) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof CustomerUpdateMsg) { if (message instanceof CustomerUpdateMsg customerUpdateMsg) {
CustomerUpdateMsg customerUpdateMsg = (CustomerUpdateMsg) message;
Customer customer = JacksonUtil.fromString(customerUpdateMsg.getEntity(), Customer.class, true); Customer customer = JacksonUtil.fromString(customerUpdateMsg.getEntity(), Customer.class, true);
Assert.assertNotNull(customer); Assert.assertNotNull(customer);
if (msgType.equals(customerUpdateMsg.getMsgType()) if (msgType.equals(customerUpdateMsg.getMsgType())
@ -1117,8 +1110,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popTenantMsg(List<AbstractMessage> messages, TenantId tenantId1) { private boolean popTenantMsg(List<AbstractMessage> messages, TenantId tenantId1) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof TenantUpdateMsg) { if (message instanceof TenantUpdateMsg tenantUpdateMsg) {
TenantUpdateMsg tenantUpdateMsg = (TenantUpdateMsg) message;
Tenant tenant = JacksonUtil.fromString(tenantUpdateMsg.getEntity(), Tenant.class, true); Tenant tenant = JacksonUtil.fromString(tenantUpdateMsg.getEntity(), Tenant.class, true);
Assert.assertNotNull(tenant); Assert.assertNotNull(tenant);
if (UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE.equals(tenantUpdateMsg.getMsgType()) if (UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE.equals(tenantUpdateMsg.getMsgType())
@ -1133,8 +1125,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
private boolean popTenantProfileMsg(List<AbstractMessage> messages, TenantProfileId tenantProfileId) { private boolean popTenantProfileMsg(List<AbstractMessage> messages, TenantProfileId tenantProfileId) {
for (AbstractMessage message : messages) { for (AbstractMessage message : messages) {
if (message instanceof TenantProfileUpdateMsg) { if (message instanceof TenantProfileUpdateMsg tenantProfileUpdateMsg) {
TenantProfileUpdateMsg tenantProfileUpdateMsg = (TenantProfileUpdateMsg) message;
TenantProfile tenantProfile = JacksonUtil.fromString(tenantProfileUpdateMsg.getEntity(), TenantProfile.class, true); TenantProfile tenantProfile = JacksonUtil.fromString(tenantProfileUpdateMsg.getEntity(), TenantProfile.class, true);
Assert.assertNotNull(tenantProfile); Assert.assertNotNull(tenantProfile);
if (UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE.equals(tenantProfileUpdateMsg.getMsgType()) if (UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE.equals(tenantProfileUpdateMsg.getMsgType())
@ -1236,4 +1227,5 @@ public class EdgeControllerTest extends AbstractControllerTest {
edgeUpgradeInstructionsService.setAppVersion("3.6.2.6"); edgeUpgradeInstructionsService.setAppVersion("3.6.2.6");
Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
} }
} }

51
application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java

@ -22,11 +22,13 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
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.StringUtils;
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.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
@ -51,10 +53,13 @@ import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.data.query.KeyFilter;
import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.data.queue.QueueStats;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.queue.QueueStatsService;
import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -69,6 +74,9 @@ public class EntityQueryControllerTest extends AbstractControllerTest {
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@Autowired
private QueueStatsService queueStatsService;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
@ -593,4 +601,47 @@ public class EntityQueryControllerTest extends AbstractControllerTest {
assertThat(getErrorMessage(result)).contains("Invalid").contains("sort property"); assertThat(getErrorMessage(result)).contains("Invalid").contains("sort property");
} }
@Test
public void testFindQueueStatsEntitiesByQuery() throws Exception {
List<QueueStats> queueStatsList = new ArrayList<>();
for (int i = 0; i < 97; i++) {
QueueStats queueStats = new QueueStats();
queueStats.setQueueName(StringUtils.randomAlphabetic(5));
queueStats.setServiceId(StringUtils.randomAlphabetic(5));
queueStats.setTenantId(savedTenant.getTenantId());
queueStatsList.add(queueStatsService.save(savedTenant.getId(), queueStats));
Thread.sleep(1);
}
EntityTypeFilter entityTypeFilter = new EntityTypeFilter();
entityTypeFilter.setEntityType(EntityType.QUEUE_STATS);
EntityDataSortOrder sortOrder = new EntityDataSortOrder(
new EntityKey(EntityKeyType.ENTITY_FIELD, "queueName"), EntityDataSortOrder.Direction.ASC
);
EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, sortOrder);
List<EntityKey> entityFields = Arrays.asList(new EntityKey(EntityKeyType.ENTITY_FIELD, "queueName"),
new EntityKey(EntityKeyType.ENTITY_FIELD, "serviceId"));
EntityDataQuery query = new EntityDataQuery(entityTypeFilter, pageLink, entityFields, null, null);
PageData<EntityData> data =
doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference<PageData<EntityData>>() {
});
Assert.assertEquals(97, data.getTotalElements());
Assert.assertEquals(10, data.getTotalPages());
Assert.assertTrue(data.hasNext());
Assert.assertEquals(10, data.getData().size());
data.getData().forEach(entityData -> {
assertThat(entityData.getLatest().get(EntityKeyType.ENTITY_FIELD).get("queueName")).asString().isNotBlank();
assertThat(entityData.getLatest().get(EntityKeyType.ENTITY_FIELD).get("serviceId")).asString().isNotBlank();
});
EntityCountQuery countQuery = new EntityCountQuery(entityTypeFilter);
Long count = doPostWithResponse("/api/entitiesQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
}
} }

2
application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java

@ -494,7 +494,7 @@ public class HomePageApiTest extends AbstractControllerTest {
} }
private OAuth2Info createDefaultOAuth2Info() { private OAuth2Info createDefaultOAuth2Info() {
return new OAuth2Info(true, Lists.newArrayList( return new OAuth2Info(true, false, Lists.newArrayList(
OAuth2ParamsInfo.builder() OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList( .domainInfos(Lists.newArrayList(
OAuth2DomainInfo.builder().name("domain").scheme(SchemeType.MIXED).build() OAuth2DomainInfo.builder().name("domain").scheme(SchemeType.MIXED).build()

3
application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java

@ -1109,13 +1109,14 @@ public class UserControllerTest extends AbstractControllerTest {
private List<UserEmailInfo> getUsersInfo(PageLink pageLink) throws Exception { private List<UserEmailInfo> getUsersInfo(PageLink pageLink) throws Exception {
List<UserEmailInfo> loadedCustomerUsers = new ArrayList<>(); List<UserEmailInfo> loadedCustomerUsers = new ArrayList<>();
PageData<UserEmailInfo> pageData = null; PageData<UserEmailInfo> pageData;
do { do {
pageData = doGetTypedWithPageLink("/api/users/info?", new TypeReference<>() { pageData = doGetTypedWithPageLink("/api/users/info?", new TypeReference<>() {
}, pageLink); }, pageLink);
loadedCustomerUsers.addAll(pageData.getData()); loadedCustomerUsers.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
Assert.assertEquals(pageLink.getPageSize(), pageData.getData().size());
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
return loadedCustomerUsers; return loadedCustomerUsers;

15
application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java

@ -63,6 +63,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
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.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -85,6 +86,7 @@ import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration;
import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg;
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
@ -140,6 +142,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
installation(); installation();
edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
edgeImitator.ignoreType(OAuth2UpdateMsg.class);
edgeImitator.expectMessageAmount(21); edgeImitator.expectMessageAmount(21);
edgeImitator.connect(); edgeImitator.connect();
@ -538,6 +541,18 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
Assert.assertTrue(customer.isPublic()); Assert.assertTrue(customer.isPublic());
} }
private void validateOAuth2() throws Exception {
Optional<OAuth2UpdateMsg> oAuth2UpdateMsgOpt = edgeImitator.findMessageByType(OAuth2UpdateMsg.class);
Assert.assertTrue(oAuth2UpdateMsgOpt.isPresent());
OAuth2UpdateMsg oAuth2UpdateMsg = oAuth2UpdateMsgOpt.get();
OAuth2Info oAuth2Info = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true);
Assert.assertNotNull(oAuth2Info);
OAuth2Info auth2Info = doGet("/api/oauth2/config", OAuth2Info.class);
Assert.assertNotNull(auth2Info);
Assert.assertEquals(oAuth2Info, auth2Info);
testAutoGeneratedCodeByProtobuf(oAuth2UpdateMsg);
}
private void validateSyncCompleted() { private void validateSyncCompleted() {
Optional<SyncCompletedMsg> syncCompletedMsgOpt = edgeImitator.findMessageByType(SyncCompletedMsg.class); Optional<SyncCompletedMsg> syncCompletedMsgOpt = edgeImitator.findMessageByType(SyncCompletedMsg.class);
Assert.assertTrue(syncCompletedMsgOpt.isPresent()); Assert.assertTrue(syncCompletedMsgOpt.isPresent());

113
application/src/test/java/org/thingsboard/server/edge/OAuth2EdgeTest.java

@ -0,0 +1,113 @@
/**
* Copyright © 2016-2024 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.edge;
import com.google.common.collect.Lists;
import com.google.protobuf.AbstractMessage;
import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.oauth2.MapperType;
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2DomainInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2ParamsInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2RegistrationInfo;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
@DaoSqlTest
public class OAuth2EdgeTest extends AbstractEdgeTest {
@Test
public void testOAuth2Support() throws Exception {
loginSysAdmin();
// enable oauth
edgeImitator.allowIgnoredTypes();
edgeImitator.expectMessageAmount(1);
OAuth2Info oAuth2Info = createDefaultOAuth2Info();
oAuth2Info = doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class);
Assert.assertTrue(edgeImitator.waitForMessages());
AbstractMessage latestMessage = edgeImitator.getLatestMessage();
Assert.assertTrue(latestMessage instanceof OAuth2UpdateMsg);
OAuth2UpdateMsg oAuth2UpdateMsg = (OAuth2UpdateMsg) latestMessage;
OAuth2Info result = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true);
Assert.assertEquals(oAuth2Info, result);
// disable oauth support
edgeImitator.expectMessageAmount(1);
oAuth2Info.setEnabled(false);
oAuth2Info.setEdgeEnabled(false);
doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class);
Assert.assertTrue(edgeImitator.waitForMessages());
latestMessage = edgeImitator.getLatestMessage();
Assert.assertTrue(latestMessage instanceof OAuth2UpdateMsg);
oAuth2UpdateMsg = (OAuth2UpdateMsg) latestMessage;
result = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true);
Assert.assertEquals(oAuth2Info, result);
edgeImitator.ignoreType(OAuth2UpdateMsg.class);
loginTenantAdmin();
}
private OAuth2Info createDefaultOAuth2Info() {
return new OAuth2Info(true, true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
OAuth2DomainInfo.builder().name("domain").scheme(SchemeType.MIXED).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validRegistrationInfo()
))
.build()
));
}
private OAuth2RegistrationInfo validRegistrationInfo() {
return OAuth2RegistrationInfo.builder()
.clientId(UUID.randomUUID().toString())
.clientSecret(UUID.randomUUID().toString())
.authorizationUri(UUID.randomUUID().toString())
.accessTokenUri(UUID.randomUUID().toString())
.scope(Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString()))
.platforms(Collections.emptyList())
.userInfoUri(UUID.randomUUID().toString())
.userNameAttributeName(UUID.randomUUID().toString())
.jwkSetUri(UUID.randomUUID().toString())
.clientAuthenticationMethod(UUID.randomUUID().toString())
.loginButtonLabel(UUID.randomUUID().toString())
.mapperConfig(
OAuth2MapperConfig.builder()
.type(MapperType.CUSTOM)
.custom(
OAuth2CustomMapperConfig.builder()
.url(UUID.randomUUID().toString())
.build()
)
.build()
)
.build();
}
}

6
application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java

@ -44,6 +44,7 @@ import org.thingsboard.server.gen.edge.v1.DownlinkResponseMsg;
import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration;
import org.thingsboard.server.gen.edge.v1.EntityDataProto; import org.thingsboard.server.gen.edge.v1.EntityDataProto;
import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg; import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg;
import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg; import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg;
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg; import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg;
@ -314,6 +315,11 @@ public class EdgeImitator {
result.add(saveDownlinkMsg(resourceUpdateMsg)); result.add(saveDownlinkMsg(resourceUpdateMsg));
} }
} }
if (downlinkMsg.getOAuth2UpdateMsgCount() > 0) {
for (OAuth2UpdateMsg oAuth2UpdateMsg : downlinkMsg.getOAuth2UpdateMsgList()) {
result.add(saveDownlinkMsg(oAuth2UpdateMsg));
}
}
if (downlinkMsg.hasEdgeConfiguration()) { if (downlinkMsg.hasEdgeConfiguration()) {
result.add(saveDownlinkMsg(downlinkMsg.getEdgeConfiguration())); result.add(saveDownlinkMsg(downlinkMsg.getEdgeConfiguration()));
} }

25
application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorTest.java

@ -46,6 +46,7 @@ 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.edge.EdgeSynchronizationManager; import org.thingsboard.server.dao.edge.EdgeSynchronizationManager;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
@ -81,6 +82,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstruct
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorV1; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorV1;
import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorV2; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorV2;
import org.thingsboard.server.service.edge.rpc.constructor.oauth2.OAuth2MsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorV1; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorV1;
import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorV2; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorV2;
@ -128,6 +130,7 @@ import org.thingsboard.server.service.edge.rpc.processor.device.profile.DevicePr
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorV1; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorV1;
import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorV2; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorV2;
import org.thingsboard.server.service.edge.rpc.processor.oauth2.OAuth2EdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorFactory;
import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorV1; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorV1;
import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorV2; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorV2;
@ -239,6 +242,9 @@ public abstract class BaseEdgeProcessorTest {
@MockBean @MockBean
protected ResourceService resourceService; protected ResourceService resourceService;
@MockBean
protected OAuth2Service oAuth2Service;
@MockBean @MockBean
@Lazy @Lazy
protected TbQueueProducerProvider producerProvider; protected TbQueueProducerProvider producerProvider;
@ -360,6 +366,9 @@ public abstract class BaseEdgeProcessorTest {
@MockBean @MockBean
protected WidgetMsgConstructorV2 widgetMsgConstructorV2; protected WidgetMsgConstructorV2 widgetMsgConstructorV2;
@MockBean
protected OAuth2MsgConstructor oAuth2MsgConstructor;
@MockBean @MockBean
protected AlarmEdgeProcessorV1 alarmProcessorV1; protected AlarmEdgeProcessorV1 alarmProcessorV1;
@ -417,6 +426,9 @@ public abstract class BaseEdgeProcessorTest {
@MockBean @MockBean
protected RelationEdgeProcessorV2 relationEdgeProcessorV2; protected RelationEdgeProcessorV2 relationEdgeProcessorV2;
@MockBean
protected OAuth2EdgeProcessor oAuth2EdgeProcessor;
@SpyBean @SpyBean
protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory; protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory;
@ -514,17 +526,18 @@ public abstract class BaseEdgeProcessorTest {
} }
protected static Stream<Arguments> provideParameters() { protected static Stream<Arguments> provideParameters() {
UUID dashoboardUUID = UUID.randomUUID(); UUID dashboardUUID = UUID.randomUUID();
UUID ruleChaindUUID = UUID.randomUUID(); UUID ruleChainUUID = UUID.randomUUID();
return Stream.of( return Stream.of(
Arguments.of(EdgeVersion.V_3_3_0, 0, 0, 0, 0), Arguments.of(EdgeVersion.V_3_3_0, 0, 0, 0, 0),
Arguments.of(EdgeVersion.V_3_3_3, 0, 0, 0, 0), Arguments.of(EdgeVersion.V_3_3_3, 0, 0, 0, 0),
Arguments.of(EdgeVersion.V_3_4_0, 0, 0, 0, 0), Arguments.of(EdgeVersion.V_3_4_0, 0, 0, 0, 0),
Arguments.of(EdgeVersion.V_3_6_0, Arguments.of(EdgeVersion.V_3_6_0,
dashoboardUUID.getMostSignificantBits(), dashboardUUID.getMostSignificantBits(),
dashoboardUUID.getLeastSignificantBits(), dashboardUUID.getLeastSignificantBits(),
ruleChaindUUID.getMostSignificantBits(), ruleChainUUID.getMostSignificantBits(),
ruleChaindUUID.getLeastSignificantBits()) ruleChainUUID.getLeastSignificantBits())
); );
} }
} }

40
application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/TelemetryEdgeProcessorTest.java

@ -16,27 +16,51 @@
package org.thingsboard.server.service.edge.rpc.processor.telemetry; package org.thingsboard.server.service.edge.rpc.processor.telemetry;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg;
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessorTest;
@Slf4j import static org.mockito.ArgumentMatchers.any;
@RunWith(MockitoJUnitRunner.class) import static org.mockito.Mockito.verify;
public class TelemetryEdgeProcessorTest {
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {TelemetryEdgeProcessor.class})
@TestPropertySource(properties = {
"edges.rpc.max_telemetry_message_size=1000"
})
public class TelemetryEdgeProcessorTest extends BaseEdgeProcessorTest {
@SpyBean
private TelemetryEdgeProcessor telemetryEdgeProcessor;
@MockBean
private NotificationRuleProcessor notificationRuleProcessor;
@Test @Test
public void testConvert_maxSizeLimit() throws Exception { public void testConvert_maxSizeLimit() {
Edge edge = new Edge();
EdgeEvent edgeEvent = new EdgeEvent(); EdgeEvent edgeEvent = new EdgeEvent();
ObjectNode body = JacksonUtil.newObjectNode(); ObjectNode body = JacksonUtil.newObjectNode();
body.put("value", StringUtils.randomAlphanumeric(10000)); body.put("value", StringUtils.randomAlphanumeric(1000));
edgeEvent.setBody(body); edgeEvent.setBody(body);
DownlinkMsg downlinkMsg = new TelemetryEdgeProcessor().convertTelemetryEventToDownlink(edgeEvent);
DownlinkMsg downlinkMsg = telemetryEdgeProcessor.convertTelemetryEventToDownlink(edge, edgeEvent);
Assert.assertNull(downlinkMsg); Assert.assertNull(downlinkMsg);
verify(notificationRuleProcessor, Mockito.times(1)).process(any());
} }
} }

80
application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java

@ -15,23 +15,29 @@
*/ */
package org.thingsboard.server.service.script; package org.thingsboard.server.service.script;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert; import org.junit.Assert;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.TbStopWatch;
import org.thingsboard.script.api.ScriptType; import org.thingsboard.script.api.ScriptType;
import org.thingsboard.script.api.js.NashornJsInvokeService; import org.thingsboard.script.api.js.NashornJsInvokeService;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
@ -41,8 +47,9 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_RE
"js.max_script_body_size=50", "js.max_script_body_size=50",
"js.max_total_args_size=50", "js.max_total_args_size=50",
"js.max_result_size=50", "js.max_result_size=50",
"js.local.max_errors=2" "js.local.max_errors=2",
}) })
@Slf4j
class NashornJsInvokeServiceTest extends AbstractControllerTest { class NashornJsInvokeServiceTest extends AbstractControllerTest {
@Autowired @Autowired
@ -56,23 +63,64 @@ class NashornJsInvokeServiceTest extends AbstractControllerTest {
int iterations = 1000; int iterations = 1000;
UUID scriptId = evalScript("return msg.temperature > 20"); UUID scriptId = evalScript("return msg.temperature > 20");
// warmup // warmup
ObjectNode msg = JacksonUtil.newObjectNode(); log.info("Warming up 1000 times...");
for (int i = 0; i < 100; i++) { var warmupWatch = TbStopWatch.create();
msg.put("temperature", i); for (int i = 0; i < 1000; i++) {
boolean expected = i > 20; boolean expected = i > 20;
boolean result = Boolean.valueOf(invokeScript(scriptId, JacksonUtil.toString(msg))); boolean result = Boolean.parseBoolean(invokeScript(scriptId, "{\"temperature\":" + i + "}"));
Assert.assertEquals(expected, result); Assert.assertEquals(expected, result);
} }
long startTs = System.currentTimeMillis(); log.info("Warming up finished in {} ms", warmupWatch.stopAndGetTotalTimeMillis());
log.info("Starting performance test...");
var watch = TbStopWatch.create();
for (int i = 0; i < iterations; i++) { for (int i = 0; i < iterations; i++) {
msg.put("temperature", i);
boolean expected = i > 20; boolean expected = i > 20;
boolean result = Boolean.valueOf(invokeScript(scriptId, JacksonUtil.toString(msg))); boolean result = Boolean.parseBoolean(invokeScript(scriptId, "{\"temperature\":" + i + "}"));
log.debug("asserting result");
Assert.assertEquals(expected, result); Assert.assertEquals(expected, result);
} }
long duration = System.currentTimeMillis() - startTs; long duration = watch.stopAndGetTotalTimeMillis();
System.out.println(iterations + " invocations took: " + duration + "ms"); log.info("Performance test with {} invocations took: {} ms", iterations, duration);
Assert.assertTrue(duration < TimeUnit.MINUTES.toMillis(4)); assertThat(duration).as("duration ms")
.isLessThan(TimeUnit.MINUTES.toMillis(1)); // effective exec time is about 500ms
}
@Test
void givenSimpleScriptMultiThreadTestPerformance() throws ExecutionException, InterruptedException, TimeoutException {
int iterations = 1000*4;
List<ListenableFuture<Object>> futures = new ArrayList<>(iterations);
UUID scriptId = evalScript("return msg.temperature > 20 ;");
// warmup
log.info("Warming up 1000 times...");
var warmupWatch = TbStopWatch.create();
for (int i = 0; i < 1000; i++) {
futures.add(invokeScriptAsync(scriptId, "{\"temperature\":" + i + "}"));
}
List<Object> results = Futures.allAsList(futures).get(1, TimeUnit.MINUTES);
for (int i = 0; i < 1000; i++) {
boolean expected = i > 20;
boolean result = Boolean.parseBoolean(results.get(i).toString());
Assert.assertEquals(expected, result);
}
log.info("Warming up finished in {} ms", warmupWatch.stopAndGetTotalTimeMillis());
futures.clear();
log.info("Starting performance test...");
var watch = TbStopWatch.create();
for (int i = 0; i < iterations; i++) {
futures.add(invokeScriptAsync(scriptId, "{\"temperature\":" + i + "}"));
}
results = Futures.allAsList(futures).get(1, TimeUnit.MINUTES);
for (int i = 0; i < iterations; i++) {
boolean expected = i > 20;
boolean result = Boolean.parseBoolean(results.get(i).toString());
Assert.assertEquals(expected, result);
}
long duration = watch.stopAndGetTotalTimeMillis();
log.info("Performance test with {} invocations took: {} ms", iterations, duration);
assertThat(duration).as("duration ms")
.isLessThan(TimeUnit.MINUTES.toMillis(1)); // effective exec time is about 500ms
} }
@Test @Test
@ -122,7 +170,11 @@ class NashornJsInvokeServiceTest extends AbstractControllerTest {
} }
private String invokeScript(UUID scriptId, String msg) throws ExecutionException, InterruptedException { private String invokeScript(UUID scriptId, String msg) throws ExecutionException, InterruptedException {
return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString(); return invokeScriptAsync(scriptId, msg).get().toString();
}
private ListenableFuture<Object> invokeScriptAsync(UUID scriptId, String msg) {
return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name());
} }
} }

2
application/src/test/resources/logback-test.xml

@ -16,7 +16,7 @@
<logger name="org.testcontainers" level="INFO" /> <logger name="org.testcontainers" level="INFO" />
<logger name="org.eclipse.leshan" level="INFO"/> <logger name="org.eclipse.leshan" level="INFO"/>
<logger name="org.thingsboard.server.controller.AbstractWebTest" level="INFO"/> <logger name="org.thingsboard.server.controller.AbstractWebTest" level="INFO"/>
<logger name="org.thingsboard.server.service.script" level="INFO"/>
<!-- mute TelemetryEdgeSqlTest that causes a lot of randomly generated errors --> <!-- mute TelemetryEdgeSqlTest that causes a lot of randomly generated errors -->
<logger name="org.thingsboard.server.service.edge.rpc.EdgeGrpcSession" level="OFF"/> <logger name="org.thingsboard.server.service.edge.rpc.EdgeGrpcSession" level="OFF"/>

2
common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java

@ -106,6 +106,8 @@ public interface AlarmService extends EntityDaoService {
PageData<AlarmId> findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, PageLink pageLink); PageData<AlarmId> findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, PageLink pageLink);
PageData<AlarmId> findAlarmIdsByOriginatorId(TenantId tenantId, EntityId originatorId, PageLink pageLink);
void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId); void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId);
void deleteEntityAlarmRecordsByTenantId(TenantId tenantId); void deleteEntityAlarmRecordsByTenantId(TenantId tenantId);

1
common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java

@ -24,6 +24,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface OAuth2Service { public interface OAuth2Service {
List<OAuth2ClientInfo> getOAuth2Clients(String domainScheme, String domainName, String pkgName, PlatformType platformType); List<OAuth2ClientInfo> getOAuth2Clients(String domainScheme, String domainName, String pkgName, PlatformType platformType);
void saveOAuth2Info(OAuth2Info oauth2Info); void saveOAuth2Info(OAuth2Info oauth2Info);

37
common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueStatsService.java

@ -0,0 +1,37 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.queue;
import org.thingsboard.server.common.data.id.QueueStatsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.QueueStats;
import org.thingsboard.server.dao.entity.EntityDaoService;
import java.util.List;
public interface QueueStatsService extends EntityDaoService {
QueueStats save(TenantId tenantId, QueueStats queueStats);
QueueStats findQueueStatsById(TenantId tenantId, QueueStatsId queueStatsId);
QueueStats findByTenantIdAndNameAndServiceId(TenantId tenantId, String queueName, String serviceId);
List<QueueStats> findByTenantId(TenantId tenantId);
void deleteByTenantId(TenantId tenantId);
}

6
common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java

@ -26,7 +26,6 @@ import java.util.stream.Collectors;
* @author Andrew Shvayka * @author Andrew Shvayka
*/ */
public enum EntityType { public enum EntityType {
TENANT(1), TENANT(1),
CUSTOMER(2), CUSTOMER(2),
USER(3), USER(3),
@ -59,12 +58,13 @@ public enum EntityType {
NOTIFICATION_TEMPLATE (30), NOTIFICATION_TEMPLATE (30),
NOTIFICATION_REQUEST (31), NOTIFICATION_REQUEST (31),
NOTIFICATION (32), NOTIFICATION (32),
NOTIFICATION_RULE (33); NOTIFICATION_RULE (33),
QUEUE_STATS(34);
@Getter @Getter
private final int protoNumber; // Corresponds to EntityTypeProto private final int protoNumber; // Corresponds to EntityTypeProto
EntityType(int protoNumber) { private EntityType(int protoNumber) {
this.protoNumber = protoNumber; this.protoNumber = protoNumber;
} }

3
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java

@ -41,7 +41,8 @@ public enum EdgeEventType {
ADMIN_SETTINGS(true, null), ADMIN_SETTINGS(true, null),
OTA_PACKAGE(true, EntityType.OTA_PACKAGE), OTA_PACKAGE(true, EntityType.OTA_PACKAGE),
QUEUE(true, EntityType.QUEUE), QUEUE(true, EntityType.QUEUE),
TB_RESOURCE(true, EntityType.TB_RESOURCE); TB_RESOURCE(true, EntityType.TB_RESOURCE),
OAUTH2(true, null);
private final boolean allEdgesRelated; private final boolean allEdgesRelated;

2
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java

@ -103,6 +103,8 @@ public class EntityIdFactory {
return new NotificationTemplateId(uuid); return new NotificationTemplateId(uuid);
case NOTIFICATION: case NOTIFICATION:
return new NotificationId(uuid); return new NotificationId(uuid);
case QUEUE_STATS:
return new QueueStatsId(uuid);
} }
throw new IllegalArgumentException("EntityType " + type + " is not supported!"); throw new IllegalArgumentException("EntityType " + type + " is not supported!");
} }

43
common/data/src/main/java/org/thingsboard/server/common/data/id/QueueStatsId.java

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
public class QueueStatsId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@JsonCreator
public QueueStatsId(@JsonProperty("id") UUID id) {
super(id);
}
public static QueueStatsId fromString(String queueId) {
return new QueueStatsId(UUID.fromString(queueId));
}
@Schema(required = true, description = "string", example = "QUEUE_STATS", allowableValues = "QUEUE_STATS")
@Override
public EntityType getEntityType() {
return EntityType.QUEUE_STATS;
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/id/UUIDBased.java

@ -68,7 +68,7 @@ public abstract class UUIDBased implements HasUUID, Serializable {
@Override @Override
public String toString() { public String toString() {
return id.toString(); return String.valueOf(id);
} }
} }

2
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java

@ -35,6 +35,8 @@ import java.util.List;
public class OAuth2Info { public class OAuth2Info {
@Schema(description = "Whether OAuth2 settings are enabled or not") @Schema(description = "Whether OAuth2 settings are enabled or not")
private boolean enabled; private boolean enabled;
@Schema(description = "Whether OAuth2 settings are enabled on Edge or not")
private boolean edgeEnabled;
@Schema(description = "List of configured OAuth2 clients. Cannot contain null values", required = true) @Schema(description = "List of configured OAuth2 clients. Cannot contain null values", required = true)
private List<OAuth2ParamsInfo> oauth2ParamsInfos; private List<OAuth2ParamsInfo> oauth2ParamsInfos;
} }

2
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java

@ -30,11 +30,13 @@ import org.thingsboard.server.common.data.id.TenantId;
public class OAuth2Params extends BaseData<OAuth2ParamsId> { public class OAuth2Params extends BaseData<OAuth2ParamsId> {
private boolean enabled; private boolean enabled;
private boolean edgeEnabled;
private TenantId tenantId; private TenantId tenantId;
public OAuth2Params(OAuth2Params oauth2Params) { public OAuth2Params(OAuth2Params oauth2Params) {
super(oauth2Params); super(oauth2Params);
this.enabled = oauth2Params.enabled; this.enabled = oauth2Params.enabled;
this.edgeEnabled = oauth2Params.edgeEnabled;
this.tenantId = oauth2Params.tenantId; this.tenantId = oauth2Params.tenantId;
} }
} }

26
common/data/src/main/java/org/thingsboard/server/common/data/page/PageLink.java

@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import java.util.ArrayList;
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;
@ -65,19 +66,19 @@ public class PageLink {
return new PageLink(this.pageSize, this.page+1, this.textSearch, this.sortOrder); return new PageLink(this.pageSize, this.page+1, this.textSearch, this.sortOrder);
} }
public Sort toSort(SortOrder sortOrder, Map<String,String> columnMap) { public Sort toSort(SortOrder sortOrder, Map<String,String> columnMap, boolean addDefaultSorting) {
if (sortOrder == null) { if (sortOrder == null) {
return DEFAULT_SORT; return DEFAULT_SORT;
} else { } else {
String property = sortOrder.getProperty(); return toSort(List.of(sortOrder), columnMap, addDefaultSorting);
if (columnMap.containsKey(property)) {
property = columnMap.get(property);
}
return Sort.by(Sort.Direction.fromString(sortOrder.getDirection().name()), property);
} }
} }
public Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap) { public Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap, boolean addDefaultSorting) {
if (addDefaultSorting && !isDefaultSortOrderAvailable(sortOrders)) {
sortOrders = new ArrayList<>(sortOrders);
sortOrders.add(new SortOrder(DEFAULT_SORT_PROPERTY, SortOrder.Direction.ASC));
}
return Sort.by(sortOrders.stream().map(s -> toSortOrder(s, columnMap)).collect(Collectors.toList())); return Sort.by(sortOrders.stream().map(s -> toSortOrder(s, columnMap)).collect(Collectors.toList()));
} }
@ -86,7 +87,16 @@ public class PageLink {
if (columnMap.containsKey(property)) { if (columnMap.containsKey(property)) {
property = columnMap.get(property); property = columnMap.get(property);
} }
return new Sort.Order(Sort.Direction.fromString(sortOrder.getDirection().name()), property, Sort.NullHandling.NULLS_LAST); return new Sort.Order(Sort.Direction.fromString(sortOrder.getDirection().name()), property);
}
public boolean isDefaultSortOrderAvailable(List<SortOrder> sortOrders) {
for (SortOrder sortOrder : sortOrders) {
if (DEFAULT_SORT_PROPERTY.equals(sortOrder.getProperty())) {
return true;
}
}
return false;
} }
} }

30
common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageLink.java

@ -19,11 +19,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.domain.Sort;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Data @Data
@ToString(callSuper = true) @ToString(callSuper = true)
@ -67,29 +62,4 @@ public class TimePageLink extends PageLink {
this.startTime, this.endTime); this.startTime, this.endTime);
} }
@Override
public Sort toSort(SortOrder sortOrder, Map<String,String> columnMap) {
if (sortOrder == null) {
return super.toSort(sortOrder, columnMap);
} else {
return toSort(new ArrayList<>(List.of(sortOrder)), columnMap);
}
}
@Override
public Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap) {
if (!isDefaultSortOrderAvailable(sortOrders)) {
sortOrders.add(new SortOrder(DEFAULT_SORT_PROPERTY, SortOrder.Direction.ASC));
}
return super.toSort(sortOrders, columnMap);
}
private boolean isDefaultSortOrderAvailable(List<SortOrder> sortOrders) {
for (SortOrder sortOrder : sortOrders) {
if (DEFAULT_SORT_PROPERTY.equals(sortOrder.getProperty())) {
return true;
}
}
return false;
}
} }

39
common/data/src/main/java/org/thingsboard/server/common/data/queue/QueueStats.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.queue;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.QueueStatsId;
@EqualsAndHashCode(callSuper = true)
@Data
public class QueueStats extends BaseData<QueueStatsId> implements HasTenantId {
private TenantId tenantId;
private String queueName;
private String serviceId;
public QueueStats() {
}
public QueueStats(QueueStatsId id) {
super(id);
}
}

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadRequest.java

@ -26,6 +26,7 @@ import java.util.Map;
public class EntityTypeVersionLoadRequest extends VersionLoadRequest { public class EntityTypeVersionLoadRequest extends VersionLoadRequest {
private Map<EntityType, EntityTypeVersionLoadConfig> entityTypes; private Map<EntityType, EntityTypeVersionLoadConfig> entityTypes;
private boolean rollbackOnError;
@Override @Override
public VersionLoadRequestType getType() { public VersionLoadRequestType getType() {

6
common/edge-api/src/main/proto/edge.proto

@ -37,6 +37,7 @@ enum EdgeVersion {
V_3_6_0 = 3; V_3_6_0 = 3;
V_3_6_1 = 4; V_3_6_1 = 4;
V_3_6_2 = 5; V_3_6_2 = 5;
V_3_7_0 = 6;
} }
/** /**
@ -467,6 +468,10 @@ message ResourceUpdateMsg {
string entity = 11; string entity = 11;
} }
message OAuth2UpdateMsg {
string entity = 1;
}
message RuleChainMetadataRequestMsg { message RuleChainMetadataRequestMsg {
int64 ruleChainIdMSB = 1; int64 ruleChainIdMSB = 1;
int64 ruleChainIdLSB = 2; int64 ruleChainIdLSB = 2;
@ -668,5 +673,6 @@ message DownlinkMsg {
repeated TenantProfileUpdateMsg tenantProfileUpdateMsg = 27; repeated TenantProfileUpdateMsg tenantProfileUpdateMsg = 27;
repeated ResourceUpdateMsg resourceUpdateMsg = 28; repeated ResourceUpdateMsg resourceUpdateMsg = 28;
repeated AlarmCommentUpdateMsg alarmCommentUpdateMsg = 29; repeated AlarmCommentUpdateMsg alarmCommentUpdateMsg = 29;
repeated OAuth2UpdateMsg oAuth2UpdateMsg = 30;
} }

150
common/proto/src/main/java/org/thingsboard/server/common/util/KvProtoUtil.java

@ -29,11 +29,26 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class KvProtoUtil { public class KvProtoUtil {
private static final DataType[] dataTypeByProtoNumber;
static {
int arraySize = Arrays.stream(DataType.values()).mapToInt(DataType::getProtoNumber).max().orElse(0);
dataTypeByProtoNumber = new DataType[arraySize + 1];
Arrays.stream(DataType.values()).forEach(dataType -> dataTypeByProtoNumber[dataType.getProtoNumber()] = dataType);
}
public static List<AttributeKvEntry> toAttributeKvList(List<TransportProtos.TsKvProto> dataList) {
List<AttributeKvEntry> result = new ArrayList<>(dataList.size());
dataList.forEach(proto -> result.add(new BaseAttributeKvEntry(fromTsKvProto(proto.getKv()), proto.getTs())));
return result;
}
public static List<TransportProtos.TsKvProto> attrToTsKvProtos(List<AttributeKvEntry> result) { public static List<TransportProtos.TsKvProto> attrToTsKvProtos(List<AttributeKvEntry> result) {
List<TransportProtos.TsKvProto> clientAttributes; List<TransportProtos.TsKvProto> clientAttributes;
if (result == null || result.isEmpty()) { if (result == null || result.isEmpty()) {
@ -47,8 +62,7 @@ public class KvProtoUtil {
return clientAttributes; return clientAttributes;
} }
public static List<TransportProtos.TsKvProto> toTsKvProtoList(List<TsKvEntry> result) {
public static List<TransportProtos.TsKvProto> tsToTsKvProtos(List<TsKvEntry> result) {
List<TransportProtos.TsKvProto> ts; List<TransportProtos.TsKvProto> ts;
if (result == null || result.isEmpty()) { if (result == null || result.isEmpty()) {
ts = Collections.emptyList(); ts = Collections.emptyList();
@ -61,95 +75,85 @@ public class KvProtoUtil {
return ts; return ts;
} }
public static List<TsKvEntry> fromTsKvProtoList(List<TransportProtos.TsKvProto> dataList) {
List<TsKvEntry> result = new ArrayList<>(dataList.size());
dataList.forEach(proto -> result.add(new BasicTsKvEntry(proto.getTs(), fromTsKvProto(proto.getKv()))));
return result;
}
public static TransportProtos.TsKvProto toTsKvProto(long ts, KvEntry kvEntry) { public static TransportProtos.TsKvProto toTsKvProto(long ts, KvEntry kvEntry) {
return TransportProtos.TsKvProto.newBuilder().setTs(ts) return TransportProtos.TsKvProto.newBuilder().setTs(ts)
.setKv(KvProtoUtil.toKeyValueProto(kvEntry)).build(); .setKv(KvProtoUtil.toKeyValueTypeProto(kvEntry)).build();
}
public static TsKvEntry fromTsKvProto(TransportProtos.TsKvProto proto) {
return new BasicTsKvEntry(proto.getTs(), fromTsKvProto(proto.getKv()));
} }
public static TransportProtos.KeyValueProto toKeyValueProto(KvEntry kvEntry) { public static TransportProtos.KeyValueProto toKeyValueTypeProto(KvEntry kvEntry) {
TransportProtos.KeyValueProto.Builder builder = TransportProtos.KeyValueProto.newBuilder(); TransportProtos.KeyValueProto.Builder builder = TransportProtos.KeyValueProto.newBuilder();
builder.setKey(kvEntry.getKey()); builder.setKey(kvEntry.getKey());
builder.setType(toKeyValueTypeProto(kvEntry.getDataType()));
switch (kvEntry.getDataType()) { switch (kvEntry.getDataType()) {
case BOOLEAN: case BOOLEAN -> kvEntry.getBooleanValue().ifPresent(builder::setBoolV);
builder.setType(TransportProtos.KeyValueType.BOOLEAN_V); case LONG -> kvEntry.getLongValue().ifPresent(builder::setLongV);
builder.setBoolV(kvEntry.getBooleanValue().get()); case DOUBLE -> kvEntry.getDoubleValue().ifPresent(builder::setDoubleV);
break; case JSON -> kvEntry.getJsonValue().ifPresent(builder::setJsonV);
case DOUBLE: case STRING -> kvEntry.getStrValue().ifPresent(builder::setStringV);
builder.setType(TransportProtos.KeyValueType.DOUBLE_V);
builder.setDoubleV(kvEntry.getDoubleValue().get());
break;
case LONG:
builder.setType(TransportProtos.KeyValueType.LONG_V);
builder.setLongV(kvEntry.getLongValue().get());
break;
case STRING:
builder.setType(TransportProtos.KeyValueType.STRING_V);
builder.setStringV(kvEntry.getStrValue().get());
break;
case JSON:
builder.setType(TransportProtos.KeyValueType.JSON_V);
builder.setJsonV(kvEntry.getJsonValue().get());
break;
} }
return builder.build(); return builder.build();
} }
public static TransportProtos.TsKvProto.Builder toKeyValueProto(long ts, KvEntry attr) { public static KvEntry fromTsKvProto(TransportProtos.KeyValueProto proto) {
TransportProtos.KeyValueProto.Builder dataBuilder = TransportProtos.KeyValueProto.newBuilder(); return switch (fromKeyValueTypeProto(proto.getType())) {
dataBuilder.setKey(attr.getKey()); case BOOLEAN -> new BooleanDataEntry(proto.getKey(), proto.getBoolV());
dataBuilder.setType(TransportProtos.KeyValueType.forNumber(attr.getDataType().ordinal())); case LONG -> new LongDataEntry(proto.getKey(), proto.getLongV());
switch (attr.getDataType()) { case DOUBLE -> new DoubleDataEntry(proto.getKey(), proto.getDoubleV());
case BOOLEAN: case STRING -> new StringDataEntry(proto.getKey(), proto.getStringV());
attr.getBooleanValue().ifPresent(dataBuilder::setBoolV); case JSON -> new JsonDataEntry(proto.getKey(), proto.getJsonV());
break; };
case LONG:
attr.getLongValue().ifPresent(dataBuilder::setLongV);
break;
case DOUBLE:
attr.getDoubleValue().ifPresent(dataBuilder::setDoubleV);
break;
case JSON:
attr.getJsonValue().ifPresent(dataBuilder::setJsonV);
break;
case STRING:
attr.getStrValue().ifPresent(dataBuilder::setStringV);
break;
}
return TransportProtos.TsKvProto.newBuilder().setTs(ts).setKv(dataBuilder);
} }
public static List<TsKvEntry> toTsKvEntityList(List<TransportProtos.TsKvProto> dataList) { public static TransportProtos.TsKvProto.Builder toTsKvProtoBuilder(long ts, KvEntry kvEntry) {
List<TsKvEntry> result = new ArrayList<>(dataList.size()); return TransportProtos.TsKvProto.newBuilder().setTs(ts).setKv(KvProtoUtil.toKeyValueTypeProto(kvEntry));
dataList.forEach(proto -> result.add(new BasicTsKvEntry(proto.getTs(), getKvEntry(proto.getKv()))));
return result;
} }
public static List<AttributeKvEntry> toAttributeKvList(List<TransportProtos.TsKvProto> dataList) { public static List<TsKvEntry> fromTsValueProtoList(String key, List<TransportProtos.TsValueProto> dataList) {
List<AttributeKvEntry> result = new ArrayList<>(dataList.size()); List<TsKvEntry> result = new ArrayList<>(dataList.size());
dataList.forEach(proto -> result.add(new BaseAttributeKvEntry(getKvEntry(proto.getKv()), proto.getTs()))); dataList.forEach(proto -> result.add(new BasicTsKvEntry(proto.getTs(), fromTsValueProto(key, proto))));
return result; return result;
} }
private static KvEntry getKvEntry(TransportProtos.KeyValueProto proto) { public static TransportProtos.TsValueProto toTsValueProto(long ts, KvEntry attr) {
KvEntry entry = null; TransportProtos.TsValueProto.Builder dataBuilder = TransportProtos.TsValueProto.newBuilder();
DataType type = DataType.values()[proto.getType().getNumber()]; dataBuilder.setTs(ts);
switch (type) { dataBuilder.setType(toKeyValueTypeProto(attr.getDataType()));
case BOOLEAN: switch (attr.getDataType()) {
entry = new BooleanDataEntry(proto.getKey(), proto.getBoolV()); case BOOLEAN -> attr.getBooleanValue().ifPresent(dataBuilder::setBoolV);
break; case LONG -> attr.getLongValue().ifPresent(dataBuilder::setLongV);
case LONG: case DOUBLE -> attr.getDoubleValue().ifPresent(dataBuilder::setDoubleV);
entry = new LongDataEntry(proto.getKey(), proto.getLongV()); case JSON -> attr.getJsonValue().ifPresent(dataBuilder::setJsonV);
break; case STRING -> attr.getStrValue().ifPresent(dataBuilder::setStringV);
case DOUBLE:
entry = new DoubleDataEntry(proto.getKey(), proto.getDoubleV());
break;
case STRING:
entry = new StringDataEntry(proto.getKey(), proto.getStringV());
break;
case JSON:
entry = new JsonDataEntry(proto.getKey(), proto.getJsonV());
break;
} }
return entry; return dataBuilder.build();
} }
public static KvEntry fromTsValueProto(String key, TransportProtos.TsValueProto proto) {
return switch (fromKeyValueTypeProto(proto.getType())) {
case BOOLEAN -> new BooleanDataEntry(key, proto.getBoolV());
case LONG -> new LongDataEntry(key, proto.getLongV());
case DOUBLE -> new DoubleDataEntry(key, proto.getDoubleV());
case STRING -> new StringDataEntry(key, proto.getStringV());
case JSON -> new JsonDataEntry(key, proto.getJsonV());
};
}
public static TransportProtos.KeyValueType toKeyValueTypeProto(DataType dataType) {
return TransportProtos.KeyValueType.forNumber(dataType.getProtoNumber());
}
public static DataType fromKeyValueTypeProto(TransportProtos.KeyValueType keyValueType) {
return dataTypeByProtoNumber[keyValueType.getNumber()];
}
} }

65
common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java

@ -434,36 +434,28 @@ public class ProtoUtils {
} }
public static TransportProtos.ToDeviceActorNotificationMsgProto toProto(ToDeviceActorNotificationMsg msg) { public static TransportProtos.ToDeviceActorNotificationMsgProto toProto(ToDeviceActorNotificationMsg msg) {
if (msg instanceof DeviceEdgeUpdateMsg) { if (msg instanceof DeviceEdgeUpdateMsg updateMsg) {
DeviceEdgeUpdateMsg updateMsg = (DeviceEdgeUpdateMsg) msg;
TransportProtos.DeviceEdgeUpdateMsgProto proto = toProto(updateMsg); TransportProtos.DeviceEdgeUpdateMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceEdgeUpdateMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceEdgeUpdateMsg(proto).build();
} else if (msg instanceof DeviceNameOrTypeUpdateMsg) { } else if (msg instanceof DeviceNameOrTypeUpdateMsg updateMsg) {
DeviceNameOrTypeUpdateMsg updateMsg = (DeviceNameOrTypeUpdateMsg) msg;
TransportProtos.DeviceNameOrTypeUpdateMsgProto proto = toProto(updateMsg); TransportProtos.DeviceNameOrTypeUpdateMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceNameOrTypeMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceNameOrTypeMsg(proto).build();
} else if (msg instanceof DeviceAttributesEventNotificationMsg) { } else if (msg instanceof DeviceAttributesEventNotificationMsg updateMsg) {
DeviceAttributesEventNotificationMsg updateMsg = (DeviceAttributesEventNotificationMsg) msg;
TransportProtos.DeviceAttributesEventMsgProto proto = toProto(updateMsg); TransportProtos.DeviceAttributesEventMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceAttributesEventMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceAttributesEventMsg(proto).build();
} else if (msg instanceof DeviceCredentialsUpdateNotificationMsg) { } else if (msg instanceof DeviceCredentialsUpdateNotificationMsg updateMsg) {
DeviceCredentialsUpdateNotificationMsg updateMsg = (DeviceCredentialsUpdateNotificationMsg) msg;
TransportProtos.DeviceCredentialsUpdateMsgProto proto = toProto(updateMsg); TransportProtos.DeviceCredentialsUpdateMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceCredentialsUpdateMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceCredentialsUpdateMsg(proto).build();
} else if (msg instanceof ToDeviceRpcRequestActorMsg) { } else if (msg instanceof ToDeviceRpcRequestActorMsg updateMsg) {
ToDeviceRpcRequestActorMsg updateMsg = (ToDeviceRpcRequestActorMsg) msg;
TransportProtos.ToDeviceRpcRequestActorMsgProto proto = toProto(updateMsg); TransportProtos.ToDeviceRpcRequestActorMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setToDeviceRpcRequestMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setToDeviceRpcRequestMsg(proto).build();
} else if (msg instanceof FromDeviceRpcResponseActorMsg) { } else if (msg instanceof FromDeviceRpcResponseActorMsg updateMsg) {
FromDeviceRpcResponseActorMsg updateMsg = (FromDeviceRpcResponseActorMsg) msg;
TransportProtos.FromDeviceRpcResponseActorMsgProto proto = toProto(updateMsg); TransportProtos.FromDeviceRpcResponseActorMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setFromDeviceRpcResponseMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setFromDeviceRpcResponseMsg(proto).build();
} else if (msg instanceof RemoveRpcActorMsg) { } else if (msg instanceof RemoveRpcActorMsg updateMsg) {
RemoveRpcActorMsg updateMsg = (RemoveRpcActorMsg) msg;
TransportProtos.RemoveRpcActorMsgProto proto = toProto(updateMsg); TransportProtos.RemoveRpcActorMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setRemoveRpcActorMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setRemoveRpcActorMsg(proto).build();
} else if (msg instanceof DeviceDeleteMsg) { } else if (msg instanceof DeviceDeleteMsg updateMsg) {
DeviceDeleteMsg updateMsg = (DeviceDeleteMsg) msg;
TransportProtos.DeviceDeleteMsgProto proto = toProto(updateMsg); TransportProtos.DeviceDeleteMsgProto proto = toProto(updateMsg);
return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceDeleteMsg(proto).build(); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceDeleteMsg(proto).build();
} }
@ -507,24 +499,14 @@ public class ProtoUtils {
List<AttributeKvEntry> result = new ArrayList<>(); List<AttributeKvEntry> result = new ArrayList<>();
for (TransportProtos.AttributeValueProto kvEntry : valuesList) { for (TransportProtos.AttributeValueProto kvEntry : valuesList) {
boolean hasValue = kvEntry.getHasV(); boolean hasValue = kvEntry.getHasV();
KvEntry entry = null; KvEntry entry = switch (kvEntry.getType()) {
switch (kvEntry.getType()) { case BOOLEAN_V -> new BooleanDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getBoolV() : null);
case BOOLEAN_V: case LONG_V -> new LongDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getLongV() : null);
entry = new BooleanDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getBoolV() : null); case DOUBLE_V -> new DoubleDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getDoubleV() : null);
break; case STRING_V -> new StringDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getStringV() : null);
case LONG_V: case JSON_V -> new JsonDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getJsonV() : null);
entry = new LongDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getLongV() : null); default -> null;
break; };
case DOUBLE_V:
entry = new DoubleDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getDoubleV() : null);
break;
case STRING_V:
entry = new StringDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getStringV() : null);
break;
case JSON_V:
entry = new JsonDataEntry(kvEntry.getKey(), hasValue ? kvEntry.getJsonV() : null);
break;
}
result.add(new BaseAttributeKvEntry(kvEntry.getLastUpdateTs(), entry)); result.add(new BaseAttributeKvEntry(kvEntry.getLastUpdateTs(), entry));
} }
return result; return result;
@ -1029,15 +1011,11 @@ public class ProtoUtils {
.setDeviceProfileIdLSB(device.getDeviceProfileId().getId().getLeastSignificantBits()) .setDeviceProfileIdLSB(device.getDeviceProfileId().getId().getLeastSignificantBits())
.setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo())); .setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo()));
PowerSavingConfiguration psmConfiguration = null; PowerSavingConfiguration psmConfiguration = switch (device.getDeviceData().getTransportConfiguration().getType()) {
switch (device.getDeviceData().getTransportConfiguration().getType()) { case LWM2M -> (Lwm2mDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
case LWM2M: case COAP -> (CoapDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
psmConfiguration = (Lwm2mDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration(); default -> null;
break; };
case COAP:
psmConfiguration = (CoapDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
break;
}
if (psmConfiguration != null) { if (psmConfiguration != null) {
PowerMode powerMode = psmConfiguration.getPowerMode(); PowerMode powerMode = psmConfiguration.getPowerMode();
@ -1079,4 +1057,5 @@ public class ProtoUtils {
private static Long checkLong(Long l) { private static Long checkLong(Long l) {
return isNotNull(l) ? l : 0; return isNotNull(l) ? l : 0;
} }
} }

1
common/proto/src/main/proto/queue.proto

@ -54,6 +54,7 @@ enum EntityTypeProto {
NOTIFICATION_REQUEST = 31; NOTIFICATION_REQUEST = 31;
NOTIFICATION = 32; NOTIFICATION = 32;
NOTIFICATION_RULE = 33; NOTIFICATION_RULE = 33;
QUEUE_STATS = 34;
} }
/** /**

118
common/proto/src/test/java/org/thingsboard/server/common/util/KvProtoUtilTest.java

@ -0,0 +1,118 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.util;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.thingsboard.server.common.data.kv.AggTsKvEntry;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.kv.DoubleDataEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
class KvProtoUtilTest {
private static final long TS = System.currentTimeMillis();
private static Stream<KvEntry> kvEntryData() {
String key = "key";
return Stream.of(
new BooleanDataEntry(key, true),
new LongDataEntry(key, 23L),
new DoubleDataEntry(key, 23.0),
new StringDataEntry(key, "stringValue"),
new JsonDataEntry(key, "jsonValue")
);
}
private static Stream<KvEntry> basicTsKvEntryData() {
return kvEntryData().map(kvEntry -> new BasicTsKvEntry(TS, kvEntry));
}
private static Stream<List<BaseAttributeKvEntry>> attributeKvEntryData() {
return Stream.of(kvEntryData().map(kvEntry -> new BaseAttributeKvEntry(TS, kvEntry)).toList());
}
private static List<TsKvEntry> createTsKvEntryList(boolean withAggregation) {
return kvEntryData().map(kvEntry -> {
if (withAggregation) {
return new AggTsKvEntry(TS, kvEntry, 0);
} else {
return new BasicTsKvEntry(TS, kvEntry);
}
}).collect(Collectors.toList());
}
@ParameterizedTest
@EnumSource(DataType.class)
void protoDataTypeSerialization(DataType dataType) {
assertThat(KvProtoUtil.fromKeyValueTypeProto(KvProtoUtil.toKeyValueTypeProto(dataType)))
.as(dataType.name()).isEqualTo(dataType);
}
@ParameterizedTest
@MethodSource("kvEntryData")
void protoKeyValueProtoSerialization(KvEntry kvEntry) {
assertThat(KvProtoUtil.fromTsKvProto(KvProtoUtil.toKeyValueTypeProto(kvEntry)))
.as("deserialized").isEqualTo(kvEntry);
}
@ParameterizedTest
@MethodSource("basicTsKvEntryData")
void protoTsKvEntrySerialization(KvEntry kvEntry) {
assertThat(KvProtoUtil.fromTsKvProto(KvProtoUtil.toTsKvProto(TS, kvEntry)))
.as("deserialized").isEqualTo(kvEntry);
}
@ParameterizedTest
@MethodSource("kvEntryData")
void protoTsValueSerialization(KvEntry kvEntry) {
assertThat(KvProtoUtil.fromTsValueProto(kvEntry.getKey(), KvProtoUtil.toTsValueProto(TS, kvEntry)))
.as("deserialized").isEqualTo(kvEntry);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
void protoListTsKvEntrySerialization(boolean withAggregation) {
List<TsKvEntry> tsKvEntries = createTsKvEntryList(withAggregation);
assertThat(KvProtoUtil.fromTsKvProtoList(KvProtoUtil.toTsKvProtoList(tsKvEntries)))
.as("deserialized").isEqualTo(tsKvEntries);
}
@ParameterizedTest
@MethodSource("attributeKvEntryData")
void protoListAttributeKvSerialization(List<AttributeKvEntry> attributeKvEntries) {
assertThat(KvProtoUtil.toAttributeKvList(KvProtoUtil.attrToTsKvProtos(attributeKvEntries)))
.as("deserialized")
.isEqualTo(attributeKvEntries);
}
}

30
common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java

@ -109,40 +109,40 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, transportNotificationSettings.getNotificationsTopic()); return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() {
return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, ruleEngineSettings.getTopic()); return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, ruleEngineSettings.getTopic()); return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, coreSettings.getTopic()); return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()));
} }
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() {
return new TbPubSubConsumerTemplate<>(vcAdmin, pubSubSettings, vcSettings.getTopic(), return new TbPubSubConsumerTemplate<>(vcAdmin, pubSubSettings, topicService.buildTopicName(vcSettings.getTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders())
); );
} }
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) {
return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, configuration.getTopic(), return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(configuration.getTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@ -155,7 +155,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic(), return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@ -168,13 +168,13 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() {
return new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, transportApiSettings.getRequestsTopic(), return new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() {
return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, transportApiSettings.getResponsesTopic()); return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic()));
} }
@Override @Override
@ -202,29 +202,29 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic(), return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic(), return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createVersionControlMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createVersionControlMsgProducer() {
return new TbPubSubProducerTemplate<>(vcAdmin, pubSubSettings, vcSettings.getTopic()); return new TbPubSubProducerTemplate<>(vcAdmin, pubSubSettings, topicService.buildTopicName(vcSettings.getTopic()));
} }
@PreDestroy @PreDestroy

24
common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java

@ -100,32 +100,32 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory {
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, transportNotificationSettings.getNotificationsTopic()); return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, ruleEngineSettings.getTopic()); return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() {
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, coreSettings.getTopic()); return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()));
} }
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic(), return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@ -138,13 +138,13 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory {
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() {
return new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, transportApiSettings.getRequestsTopic(), return new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() {
return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, transportApiSettings.getResponsesTopic()); return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic()));
} }
@Override @Override
@ -172,24 +172,24 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory {
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic(), return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@Override @Override
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic(), return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()));
} }
@Override @Override
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()));
} }
@Override @Override

4
common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java

@ -145,14 +145,14 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService
log.trace("[{}] InvokeScript uuid {} with timeout {}ms", tenantId, scriptId, getMaxInvokeRequestsTimeout()); log.trace("[{}] InvokeScript uuid {} with timeout {}ms", tenantId, scriptId, getMaxInvokeRequestsTimeout());
var task = doInvokeFunction(scriptId, args); var task = doInvokeFunction(scriptId, args);
var resultFuture = Futures.transformAsync(task.getResultFuture(), output -> { var resultFuture = Futures.transform(task.getResultFuture(), output -> {
String result = JacksonUtil.toString(output); String result = JacksonUtil.toString(output);
if (resultSizeExceeded(result)) { if (resultSizeExceeded(result)) {
throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new RuntimeException( throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new RuntimeException(
format("Script invocation result exceeds maximum allowed size of %s symbols", getMaxResultSize()) format("Script invocation result exceeds maximum allowed size of %s symbols", getMaxResultSize())
)); ));
} }
return Futures.immediateFuture(output); return output;
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
return withTimeoutAndStatsCallback(scriptId, task, resultFuture, invokeCallback, getMaxInvokeRequestsTimeout()); return withTimeoutAndStatsCallback(scriptId, task, resultFuture, invokeCallback, getMaxInvokeRequestsTimeout());

9
common/script/script-api/src/main/java/org/thingsboard/script/api/js/NashornJsInvokeService.java

@ -41,7 +41,6 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@Slf4j @Slf4j
@ -62,9 +61,12 @@ public class NashornJsInvokeService extends AbstractJsInvokeService {
@Value("${js.local.monitor_thread_pool_size}") @Value("${js.local.monitor_thread_pool_size}")
private int monitorThreadPoolSize; private int monitorThreadPoolSize;
@Value("${js.local.max_cpu_time}") @Value("${js.local.max_cpu_time:8000}") // 8 seconds
private long maxCpuTime; private long maxCpuTime;
@Value("${js.local.max_memory:104857600}") // 100 MiB
private long maxMemory;
@Getter @Getter
@Value("${js.local.max_errors}") @Value("${js.local.max_errors}")
private int maxErrors; private int maxErrors;
@ -107,12 +109,13 @@ public class NashornJsInvokeService extends AbstractJsInvokeService {
@Override @Override
public void init() { public void init() {
super.init(); super.init();
jsExecutor = MoreExecutors.listeningDecorator(Executors.newWorkStealingPool(jsExecutorThreadPoolSize)); jsExecutor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(jsExecutorThreadPoolSize, "nashorn-js-executor"));
if (useJsSandbox) { if (useJsSandbox) {
sandbox = NashornSandboxes.create(); sandbox = NashornSandboxes.create();
monitorExecutorService = ThingsBoardExecutors.newWorkStealingPool(monitorThreadPoolSize, "nashorn-js-monitor"); monitorExecutorService = ThingsBoardExecutors.newWorkStealingPool(monitorThreadPoolSize, "nashorn-js-monitor");
sandbox.setExecutor(monitorExecutorService); sandbox.setExecutor(monitorExecutorService);
sandbox.setMaxCPUTime(maxCpuTime); sandbox.setMaxCPUTime(maxCpuTime);
sandbox.setMaxMemory(maxMemory);
sandbox.allowNoBraces(false); sandbox.allowNoBraces(false);
sandbox.allowLoadFunctions(true); sandbox.allowLoadFunctions(true);
sandbox.setMaxPreparedStatements(30); sandbox.setMaxPreparedStatements(30);

71
common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java

@ -16,12 +16,11 @@
package org.thingsboard.server.transport.http; package org.thingsboard.server.transport.http;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -31,6 +30,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -56,6 +56,7 @@ import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetOtaPackageResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
@ -429,22 +430,17 @@ public class DeviceApiController implements TbTransportService {
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB()) .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setType(firmwareType.name()).build(); .setType(firmwareType.name()).build();
transportContext.getTransportService().process(sessionInfo, requestMsg, new GetOtaPackageCallback(responseWriter, title, version, size, chunk)); transportContext.getTransportService().process(sessionInfo, requestMsg, new GetOtaPackageCallback(transportContext, responseWriter, title, version, size, chunk));
})); }));
return responseWriter; return responseWriter;
} }
private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> { @RequiredArgsConstructor
static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> {
private final TransportContext transportContext; private final TransportContext transportContext;
private final DeferredResult<ResponseEntity> responseWriter; private final DeferredResult<ResponseEntity> responseWriter;
private final Consumer<SessionInfoProto> onSuccess; private final Consumer<SessionInfoProto> onSuccess;
DeviceAuthCallback(TransportContext transportContext, DeferredResult<ResponseEntity> responseWriter, Consumer<SessionInfoProto> onSuccess) {
this.transportContext = transportContext;
this.responseWriter = responseWriter;
this.onSuccess = onSuccess;
}
@Override @Override
public void onSuccess(ValidateDeviceCredentialsResponse msg) { public void onSuccess(ValidateDeviceCredentialsResponse msg) {
if (msg.hasDeviceInfo()) { if (msg.hasDeviceInfo()) {
@ -456,18 +452,21 @@ public class DeviceApiController implements TbTransportService {
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
log.warn("Failed to process request", e); String body = null;
responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); if (e instanceof HttpMessageNotReadableException || e instanceof JsonParseException) {
body = e.getMessage();
log.debug("Failed to process request in DeviceAuthCallback: {}", body);
} else {
log.warn("Failed to process request in DeviceAuthCallback", e);
}
responseWriter.setResult(new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR));
} }
} }
private static class DeviceProvisionCallback implements TransportServiceCallback<ProvisionDeviceResponseMsg> { @RequiredArgsConstructor
static class DeviceProvisionCallback implements TransportServiceCallback<ProvisionDeviceResponseMsg> {
private final DeferredResult<ResponseEntity> responseWriter; private final DeferredResult<ResponseEntity> responseWriter;
DeviceProvisionCallback(DeferredResult<ResponseEntity> responseWriter) {
this.responseWriter = responseWriter;
}
@Override @Override
public void onSuccess(ProvisionDeviceResponseMsg msg) { public void onSuccess(ProvisionDeviceResponseMsg msg) {
responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK)); responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK));
@ -475,25 +474,25 @@ public class DeviceApiController implements TbTransportService {
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
log.warn("Failed to process request", e); String body = null;
responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); if (e instanceof HttpMessageNotReadableException || e instanceof JsonParseException) {
body = e.getMessage();
log.debug("Failed to process request in DeviceProvisionCallback: {}", body);
} else {
log.warn("Failed to process request in DeviceProvisionCallback", e);
}
responseWriter.setResult(new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR));
} }
} }
private class GetOtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> { @RequiredArgsConstructor
static class GetOtaPackageCallback implements TransportServiceCallback<GetOtaPackageResponseMsg> {
private final TransportContext transportContext;
private final DeferredResult<ResponseEntity> responseWriter; private final DeferredResult<ResponseEntity> responseWriter;
private final String title; private final String title;
private final String version; private final String version;
private final int chuckSize; private final int chunkSize;
private final int chuck; private final int chunk;
GetOtaPackageCallback(DeferredResult<ResponseEntity> responseWriter, String title, String version, int chuckSize, int chuck) {
this.responseWriter = responseWriter;
this.title = title;
this.version = version;
this.chuckSize = chuckSize;
this.chuck = chuck;
}
@Override @Override
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg otaPackageResponseMsg) { public void onSuccess(TransportProtos.GetOtaPackageResponseMsg otaPackageResponseMsg) {
@ -501,7 +500,7 @@ public class DeviceApiController implements TbTransportService {
responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_FOUND)); responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_FOUND));
} else if (title.equals(otaPackageResponseMsg.getTitle()) && version.equals(otaPackageResponseMsg.getVersion())) { } else if (title.equals(otaPackageResponseMsg.getTitle()) && version.equals(otaPackageResponseMsg.getVersion())) {
String otaPackageId = new UUID(otaPackageResponseMsg.getOtaPackageIdMSB(), otaPackageResponseMsg.getOtaPackageIdLSB()).toString(); String otaPackageId = new UUID(otaPackageResponseMsg.getOtaPackageIdMSB(), otaPackageResponseMsg.getOtaPackageIdLSB()).toString();
ByteArrayResource resource = new ByteArrayResource(transportContext.getOtaPackageDataCache().get(otaPackageId, chuckSize, chuck)); ByteArrayResource resource = new ByteArrayResource(transportContext.getOtaPackageDataCache().get(otaPackageId, chunkSize, chunk));
ResponseEntity<ByteArrayResource> response = ResponseEntity.ok() ResponseEntity<ByteArrayResource> response = ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackageResponseMsg.getFileName()) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackageResponseMsg.getFileName())
.header("x-filename", otaPackageResponseMsg.getFileName()) .header("x-filename", otaPackageResponseMsg.getFileName())
@ -516,8 +515,14 @@ public class DeviceApiController implements TbTransportService {
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
log.warn("Failed to process request", e); String body = null;
responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); if (e instanceof HttpMessageNotReadableException || e instanceof JsonParseException) {
body = e.getMessage();
log.debug("Failed to process request in GetOtaPackageCallback: {}", body);
} else {
log.warn("Failed to process request in GetOtaPackageCallback", e);
}
responseWriter.setResult(new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR));
} }
} }

82
common/transport/http/src/test/java/org/thingsboard/server/transport/http/DeviceApiControllerTest.java

@ -0,0 +1,82 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.http;
import com.google.gson.JsonParseException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.common.transport.TransportContext;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.io.IOException;
import java.util.function.Consumer;
class DeviceApiControllerTest {
@Test
void deviceAuthCallbackTest() {
TransportContext transportContext = Mockito.mock(TransportContext.class);
DeferredResult<ResponseEntity> responseWriter = Mockito.mock(DeferredResult.class);
Consumer<TransportProtos.SessionInfoProto> onSuccess = x -> {
};
var callback = new DeviceApiController.DeviceAuthCallback(transportContext, responseWriter, onSuccess);
callback.onError(new HttpMessageNotReadableException("JSON incorrect syntax"));
callback.onError(new JsonParseException("Json ; expected"));
callback.onError(new IOException("not found"));
callback.onError(new RuntimeException("oops it is run time error"));
}
@Test
void deviceProvisionCallbackTest() {
DeferredResult<ResponseEntity> responseWriter = Mockito.mock(DeferredResult.class);
var callback = new DeviceApiController.DeviceProvisionCallback(responseWriter);
callback.onError(new HttpMessageNotReadableException("JSON incorrect syntax"));
callback.onError(new JsonParseException("Json ; expected"));
callback.onError(new IOException("not found"));
callback.onError(new RuntimeException("oops it is run time error"));
}
@Test
void getOtaPackageCallback() {
TransportContext transportContext = Mockito.mock(TransportContext.class);
DeferredResult<ResponseEntity> responseWriter = Mockito.mock(DeferredResult.class);
String title = "Title";
String version = "version";
int chunkSize = 11;
int chunk = 3;
var callback = new DeviceApiController.GetOtaPackageCallback(transportContext, responseWriter, title, version, chunkSize, chunk);
callback.onError(new HttpMessageNotReadableException("JSON incorrect syntax"));
callback.onError(new JsonParseException("Json ; expected"));
callback.onError(new IOException("not found"));
callback.onError(new RuntimeException("oops it is run time error"));
}
}

16
common/transport/http/src/test/resources/logback-test.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
logger name="org.thingsboard.server.transport.http.DeviceApiController" level="DEBUG" />
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

18
dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java

@ -56,11 +56,19 @@ public abstract class DaoUtil {
} }
public static Pageable toPageable(PageLink pageLink) { public static Pageable toPageable(PageLink pageLink) {
return toPageable(pageLink, Collections.emptyMap()); return toPageable(pageLink, true);
}
public static Pageable toPageable(PageLink pageLink, boolean addDefaultSorting) {
return toPageable(pageLink, Collections.emptyMap(), addDefaultSorting);
} }
public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap) { public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(pageLink.getSortOrder(), columnMap)); return toPageable(pageLink, columnMap, true);
}
public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap, boolean addDefaultSorting) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(pageLink.getSortOrder(), columnMap, addDefaultSorting));
} }
public static Pageable toPageable(PageLink pageLink, List<SortOrder> sortOrders) { public static Pageable toPageable(PageLink pageLink, List<SortOrder> sortOrders) {
@ -68,7 +76,11 @@ public abstract class DaoUtil {
} }
public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap, List<SortOrder> sortOrders) { public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap, List<SortOrder> sortOrders) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(sortOrders, columnMap)); return toPageable(pageLink, columnMap, sortOrders, true);
}
public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap, List<SortOrder> sortOrders, boolean addDefaultSorting) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(sortOrders, columnMap, addDefaultSorting));
} }
public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) { public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) {

2
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java

@ -80,6 +80,8 @@ public interface AlarmDao extends Dao<Alarm> {
PageData<AlarmId> findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, PageLink pageLink); PageData<AlarmId> findAlarmIdsByAssigneeId(TenantId tenantId, UUID userId, PageLink pageLink);
PageData<AlarmId> findAlarmIdsByOriginatorId(TenantId tenantId, EntityId originatorId, PageLink pageLink);
void createEntityAlarmRecord(EntityAlarm entityAlarm); void createEntityAlarmRecord(EntityAlarm entityAlarm);
List<EntityAlarm> findEntityAlarmRecords(TenantId tenantId, AlarmId id); List<EntityAlarm> findEntityAlarmRecords(TenantId tenantId, AlarmId id);

4
dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java

@ -82,14 +82,14 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al
@Override @Override
public ListenableFuture<AlarmComment> findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId) { public ListenableFuture<AlarmComment> findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId) {
log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId); log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId);
validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); validateId(alarmCommentId, id -> "Incorrect alarmCommentId " + id);
return alarmCommentDao.findAlarmCommentByIdAsync(tenantId, alarmCommentId.getId()); return alarmCommentDao.findAlarmCommentByIdAsync(tenantId, alarmCommentId.getId());
} }
@Override @Override
public AlarmComment findAlarmCommentById(TenantId tenantId, AlarmCommentId alarmCommentId) { public AlarmComment findAlarmCommentById(TenantId tenantId, AlarmCommentId alarmCommentId) {
log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId); log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId);
validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); validateId(alarmCommentId, id -> "Incorrect alarmCommentId " + id);
return alarmCommentDao.findById(tenantId, alarmCommentId.getId()); return alarmCommentDao.findById(tenantId, alarmCommentId.getId());
} }

20
dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java

@ -169,7 +169,7 @@ public class BaseAlarmService extends AbstractCachedEntityService<TenantId, Page
@Override @Override
public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId,
AlarmDataQuery query, Collection<EntityId> orderedEntityIds) { AlarmDataQuery query, Collection<EntityId> orderedEntityIds) {
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateEntityDataPageLink(query.getPageLink()); validateEntityDataPageLink(query.getPageLink());
return alarmDao.findAlarmDataByQueryForEntities(tenantId, query, orderedEntityIds); return alarmDao.findAlarmDataByQueryForEntities(tenantId, query, orderedEntityIds);
} }
@ -261,21 +261,21 @@ public class BaseAlarmService extends AbstractCachedEntityService<TenantId, Page
@Override @Override
public Alarm findAlarmById(TenantId tenantId, AlarmId alarmId) { public Alarm findAlarmById(TenantId tenantId, AlarmId alarmId) {
log.trace("Executing findAlarmById [{}]", alarmId); log.trace("Executing findAlarmById [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId); validateId(alarmId, id -> "Incorrect alarmId " + id);
return alarmDao.findAlarmById(tenantId, alarmId.getId()); return alarmDao.findAlarmById(tenantId, alarmId.getId());
} }
@Override @Override
public ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId) { public ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId) {
log.trace("Executing findAlarmByIdAsync [{}]", alarmId); log.trace("Executing findAlarmByIdAsync [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId); validateId(alarmId, id -> "Incorrect alarmId " + id);
return alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId()); return alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId());
} }
@Override @Override
public AlarmInfo findAlarmInfoById(TenantId tenantId, AlarmId alarmId) { public AlarmInfo findAlarmInfoById(TenantId tenantId, AlarmId alarmId) {
log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId); log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId); validateId(alarmId, id -> "Incorrect alarmId " + id);
return alarmDao.findAlarmInfoById(tenantId, alarmId.getId()); return alarmDao.findAlarmInfoById(tenantId, alarmId.getId());
} }
@ -302,10 +302,16 @@ public class BaseAlarmService extends AbstractCachedEntityService<TenantId, Page
@Override @Override
public PageData<AlarmId> findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, PageLink pageLink) { public PageData<AlarmId> findAlarmIdsByAssigneeId(TenantId tenantId, UserId userId, PageLink pageLink) {
log.trace("[{}] Executing findAlarmIdsByAssigneeId [{}]", tenantId, userId); log.trace("[{}] Executing findAlarmIdsByAssigneeId [{}]", tenantId, userId);
validateId(userId, "Incorrect userId " + userId); validateId(userId, id -> "Incorrect userId " + id);
return alarmDao.findAlarmIdsByAssigneeId(tenantId, userId.getId(), pageLink); return alarmDao.findAlarmIdsByAssigneeId(tenantId, userId.getId(), pageLink);
} }
@Override
public PageData<AlarmId> findAlarmIdsByOriginatorId(TenantId tenantId, EntityId originatorId, PageLink pageLink) {
log.trace("[{}] Executing findAlarmsByOriginatorId [{}]", tenantId, originatorId);
return alarmDao.findAlarmIdsByOriginatorId(tenantId, originatorId, pageLink);
}
@Override @Override
public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
AlarmStatus alarmStatus, String assigneeId) { AlarmStatus alarmStatus, String assigneeId) {
@ -336,14 +342,14 @@ public class BaseAlarmService extends AbstractCachedEntityService<TenantId, Page
@Override @Override
public long countAlarmsByQuery(TenantId tenantId, CustomerId customerId, AlarmCountQuery query) { public long countAlarmsByQuery(TenantId tenantId, CustomerId customerId, AlarmCountQuery query) {
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return alarmDao.countAlarmsByQuery(tenantId, customerId, query); return alarmDao.countAlarmsByQuery(tenantId, customerId, query);
} }
@Override @Override
public PageData<EntitySubtype> findAlarmTypesByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<EntitySubtype> findAlarmTypesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findAlarmTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findAlarmTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
if (DEFAULT_ALARM_TYPES_PAGE_LINK.equals(pageLink)) { if (DEFAULT_ALARM_TYPES_PAGE_LINK.equals(pageLink)) {
return cache.getAndPutInTransaction(tenantId, () -> return cache.getAndPutInTransaction(tenantId, () ->
alarmDao.findTenantAlarmTypes(tenantId.getId(), pageLink), false); alarmDao.findTenantAlarmTypes(tenantId.getId(), pageLink), false);

24
dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java

@ -103,7 +103,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId, boolean putInCache) { public AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId, boolean putInCache) {
log.trace("Executing findAssetProfileById [{}]", assetProfileId); log.trace("Executing findAssetProfileById [{}]", assetProfileId);
Validator.validateId(assetProfileId, INCORRECT_ASSET_PROFILE_ID + assetProfileId); Validator.validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
return cache.getOrFetchFromDB(AssetProfileCacheKey.fromId(assetProfileId), return cache.getOrFetchFromDB(AssetProfileCacheKey.fromId(assetProfileId),
() -> assetProfileDao.findById(tenantId, assetProfileId.getId()), true, putInCache); () -> assetProfileDao.findById(tenantId, assetProfileId.getId()), true, putInCache);
} }
@ -116,7 +116,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public AssetProfile findAssetProfileByName(TenantId tenantId, String profileName, boolean putInCache) { public AssetProfile findAssetProfileByName(TenantId tenantId, String profileName, boolean putInCache) {
log.trace("Executing findAssetProfileByName [{}][{}]", tenantId, profileName); log.trace("Executing findAssetProfileByName [{}][{}]", tenantId, profileName);
Validator.validateString(profileName, INCORRECT_ASSET_PROFILE_NAME + profileName); Validator.validateString(profileName, s -> INCORRECT_ASSET_PROFILE_NAME + s);
return cache.getOrFetchFromDB(AssetProfileCacheKey.fromName(tenantId, profileName), return cache.getOrFetchFromDB(AssetProfileCacheKey.fromName(tenantId, profileName),
() -> assetProfileDao.findByName(tenantId, profileName), false, putInCache); () -> assetProfileDao.findByName(tenantId, profileName), false, putInCache);
} }
@ -124,7 +124,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public AssetProfileInfo findAssetProfileInfoById(TenantId tenantId, AssetProfileId assetProfileId) { public AssetProfileInfo findAssetProfileInfoById(TenantId tenantId, AssetProfileId assetProfileId) {
log.trace("Executing findAssetProfileInfoById [{}]", assetProfileId); log.trace("Executing findAssetProfileInfoById [{}]", assetProfileId);
Validator.validateId(assetProfileId, INCORRECT_ASSET_PROFILE_ID + assetProfileId); Validator.validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
return toAssetProfileInfo(findAssetProfileById(tenantId, assetProfileId)); return toAssetProfileInfo(findAssetProfileById(tenantId, assetProfileId));
} }
@ -179,7 +179,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Transactional @Transactional
public void deleteAssetProfile(TenantId tenantId, AssetProfileId assetProfileId) { public void deleteAssetProfile(TenantId tenantId, AssetProfileId assetProfileId) {
log.trace("Executing deleteAssetProfile [{}]", assetProfileId); log.trace("Executing deleteAssetProfile [{}]", assetProfileId);
Validator.validateId(assetProfileId, INCORRECT_ASSET_PROFILE_ID + assetProfileId); Validator.validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
AssetProfile assetProfile = assetProfileDao.findById(tenantId, assetProfileId.getId()); AssetProfile assetProfile = assetProfileDao.findById(tenantId, assetProfileId.getId());
if (assetProfile != null && assetProfile.isDefault()) { if (assetProfile != null && assetProfile.isDefault()) {
throw new DataValidationException("Deletion of Default Asset Profile is prohibited!"); throw new DataValidationException("Deletion of Default Asset Profile is prohibited!");
@ -208,7 +208,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public PageData<AssetProfile> findAssetProfiles(TenantId tenantId, PageLink pageLink) { public PageData<AssetProfile> findAssetProfiles(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findAssetProfiles tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findAssetProfiles tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return assetProfileDao.findAssetProfiles(tenantId, pageLink); return assetProfileDao.findAssetProfiles(tenantId, pageLink);
} }
@ -216,7 +216,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public PageData<AssetProfileInfo> findAssetProfileInfos(TenantId tenantId, PageLink pageLink) { public PageData<AssetProfileInfo> findAssetProfileInfos(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findAssetProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findAssetProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return assetProfileDao.findAssetProfileInfos(tenantId, pageLink); return assetProfileDao.findAssetProfileInfos(tenantId, pageLink);
} }
@ -246,7 +246,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
} }
private AssetProfile doCreateDefaultAssetProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) { private AssetProfile doCreateDefaultAssetProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) {
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
AssetProfile assetProfile = new AssetProfile(); AssetProfile assetProfile = new AssetProfile();
assetProfile.setTenantId(tenantId); assetProfile.setTenantId(tenantId);
assetProfile.setDefault(defaultProfile); assetProfile.setDefault(defaultProfile);
@ -258,7 +258,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public AssetProfile findDefaultAssetProfile(TenantId tenantId) { public AssetProfile findDefaultAssetProfile(TenantId tenantId) {
log.trace("Executing findDefaultAssetProfile tenantId [{}]", tenantId); log.trace("Executing findDefaultAssetProfile tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return cache.getAndPutInTransaction(AssetProfileCacheKey.defaultProfile(tenantId), return cache.getAndPutInTransaction(AssetProfileCacheKey.defaultProfile(tenantId),
() -> assetProfileDao.findDefaultAssetProfile(tenantId), true); () -> assetProfileDao.findDefaultAssetProfile(tenantId), true);
} }
@ -266,14 +266,14 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public AssetProfileInfo findDefaultAssetProfileInfo(TenantId tenantId) { public AssetProfileInfo findDefaultAssetProfileInfo(TenantId tenantId) {
log.trace("Executing findDefaultAssetProfileInfo tenantId [{}]", tenantId); log.trace("Executing findDefaultAssetProfileInfo tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return toAssetProfileInfo(findDefaultAssetProfile(tenantId)); return toAssetProfileInfo(findDefaultAssetProfile(tenantId));
} }
@Override @Override
public boolean setDefaultAssetProfile(TenantId tenantId, AssetProfileId assetProfileId) { public boolean setDefaultAssetProfile(TenantId tenantId, AssetProfileId assetProfileId) {
log.trace("Executing setDefaultAssetProfile [{}]", assetProfileId); log.trace("Executing setDefaultAssetProfile [{}]", assetProfileId);
Validator.validateId(assetProfileId, INCORRECT_ASSET_PROFILE_ID + assetProfileId); Validator.validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
AssetProfile assetProfile = assetProfileDao.findById(tenantId, assetProfileId.getId()); AssetProfile assetProfile = assetProfileDao.findById(tenantId, assetProfileId.getId());
if (!assetProfile.isDefault()) { if (!assetProfile.isDefault()) {
assetProfile.setDefault(true); assetProfile.setDefault(true);
@ -299,7 +299,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public void deleteAssetProfilesByTenantId(TenantId tenantId) { public void deleteAssetProfilesByTenantId(TenantId tenantId) {
log.trace("Executing deleteAssetProfilesByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteAssetProfilesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantAssetProfilesRemover.removeEntities(tenantId, tenantId); tenantAssetProfilesRemover.removeEntities(tenantId, tenantId);
} }
@ -322,7 +322,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService<AssetPr
@Override @Override
public List<EntityInfo> findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) { public List<EntityInfo> findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) {
log.trace("Executing findAssetProfileNamesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findAssetProfileNamesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return assetProfileDao.findTenantAssetProfileNames(tenantId.getId(), activeOnly) return assetProfileDao.findTenantAssetProfileNames(tenantId.getId(), activeOnly)
.stream().sorted(Comparator.comparing(EntityInfo::getName)) .stream().sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList()); .collect(Collectors.toList());

81
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -75,7 +75,6 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
public static final String INCORRECT_ASSET_PROFILE_ID = "Incorrect assetProfileId "; public static final String INCORRECT_ASSET_PROFILE_ID = "Incorrect assetProfileId ";
public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
public static final String INCORRECT_ASSET_ID = "Incorrect assetId "; public static final String INCORRECT_ASSET_ID = "Incorrect assetId ";
public static final String TB_SERVICE_QUEUE = "TbServiceQueue";
@Autowired @Autowired
private AssetDao assetDao; private AssetDao assetDao;
@ -103,28 +102,28 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId) { public AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId) {
log.trace("Executing findAssetInfoById [{}]", assetId); log.trace("Executing findAssetInfoById [{}]", assetId);
validateId(assetId, INCORRECT_ASSET_ID + assetId); validateId(assetId, id -> INCORRECT_ASSET_ID + id);
return assetDao.findAssetInfoById(tenantId, assetId.getId()); return assetDao.findAssetInfoById(tenantId, assetId.getId());
} }
@Override @Override
public Asset findAssetById(TenantId tenantId, AssetId assetId) { public Asset findAssetById(TenantId tenantId, AssetId assetId) {
log.trace("Executing findAssetById [{}]", assetId); log.trace("Executing findAssetById [{}]", assetId);
validateId(assetId, INCORRECT_ASSET_ID + assetId); validateId(assetId, id -> INCORRECT_ASSET_ID + id);
return assetDao.findById(tenantId, assetId.getId()); return assetDao.findById(tenantId, assetId.getId());
} }
@Override @Override
public ListenableFuture<Asset> findAssetByIdAsync(TenantId tenantId, AssetId assetId) { public ListenableFuture<Asset> findAssetByIdAsync(TenantId tenantId, AssetId assetId) {
log.trace("Executing findAssetById [{}]", assetId); log.trace("Executing findAssetById [{}]", assetId);
validateId(assetId, INCORRECT_ASSET_ID + assetId); validateId(assetId, id -> INCORRECT_ASSET_ID + id);
return assetDao.findByIdAsync(tenantId, assetId.getId()); return assetDao.findByIdAsync(tenantId, assetId.getId());
} }
@Override @Override
public Asset findAssetByTenantIdAndName(TenantId tenantId, String name) { public Asset findAssetByTenantIdAndName(TenantId tenantId, String name) {
log.trace("Executing findAssetByTenantIdAndName [{}][{}]", tenantId, name); log.trace("Executing findAssetByTenantIdAndName [{}][{}]", tenantId, name);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return cache.getAndPutInTransaction(new AssetCacheKey(tenantId, name), return cache.getAndPutInTransaction(new AssetCacheKey(tenantId, name),
() -> assetDao.findAssetsByTenantIdAndName(tenantId.getId(), name) () -> assetDao.findAssetsByTenantIdAndName(tenantId.getId(), name)
.orElse(null), true); .orElse(null), true);
@ -199,7 +198,7 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
@Transactional @Transactional
public void deleteAsset(TenantId tenantId, AssetId assetId) { public void deleteAsset(TenantId tenantId, AssetId assetId) {
validateId(assetId, INCORRECT_ASSET_ID + assetId); validateId(assetId, id -> INCORRECT_ASSET_ID + id);
if (entityViewService.existsByTenantIdAndEntityId(tenantId, assetId)) { if (entityViewService.existsByTenantIdAndEntityId(tenantId, assetId)) {
throw new DataValidationException("Can't delete asset that has entity views!"); throw new DataValidationException("Can't delete asset that has entity views!");
} }
@ -223,7 +222,7 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<Asset> findAssetsByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<Asset> findAssetsByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findAssetsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findAssetsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetsByTenantId(tenantId.getId(), pageLink); return assetDao.findAssetsByTenantId(tenantId.getId(), pageLink);
} }
@ -231,7 +230,7 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<AssetInfo> findAssetInfosByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<AssetInfo> findAssetInfosByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findAssetInfosByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findAssetInfosByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetInfosByTenantId(tenantId.getId(), pageLink); return assetDao.findAssetInfosByTenantId(tenantId.getId(), pageLink);
} }
@ -239,8 +238,8 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { public PageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findAssetsByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); log.trace("Executing findAssetsByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetsByTenantIdAndType(tenantId.getId(), type, pageLink); return assetDao.findAssetsByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@ -248,8 +247,8 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<AssetInfo> findAssetInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { public PageData<AssetInfo> findAssetInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findAssetInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); log.trace("Executing findAssetInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetInfosByTenantIdAndType(tenantId.getId(), type, pageLink); return assetDao.findAssetInfosByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@ -257,8 +256,8 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<AssetInfo> findAssetInfosByTenantIdAndAssetProfileId(TenantId tenantId, AssetProfileId assetProfileId, PageLink pageLink) { public PageData<AssetInfo> findAssetInfosByTenantIdAndAssetProfileId(TenantId tenantId, AssetProfileId assetProfileId, PageLink pageLink) {
log.trace("Executing findAssetInfosByTenantIdAndAssetProfileId, tenantId [{}], assetProfileId [{}], pageLink [{}]", tenantId, assetProfileId, pageLink); log.trace("Executing findAssetInfosByTenantIdAndAssetProfileId, tenantId [{}], assetProfileId [{}], pageLink [{}]", tenantId, assetProfileId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(assetProfileId, INCORRECT_ASSET_PROFILE_ID + assetProfileId); validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetInfosByTenantIdAndAssetProfileId(tenantId.getId(), assetProfileId.getId(), pageLink); return assetDao.findAssetInfosByTenantIdAndAssetProfileId(tenantId.getId(), assetProfileId.getId(), pageLink);
} }
@ -266,23 +265,23 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds) { public ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds) {
log.trace("Executing findAssetsByTenantIdAndIdsAsync, tenantId [{}], assetIds [{}]", tenantId, assetIds); log.trace("Executing findAssetsByTenantIdAndIdsAsync, tenantId [{}], assetIds [{}]", tenantId, assetIds);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(assetIds, "Incorrect assetIds " + assetIds); validateIds(assetIds, ids -> "Incorrect assetIds " + ids);
return assetDao.findAssetsByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(assetIds)); return assetDao.findAssetsByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(assetIds));
} }
@Override @Override
public void deleteAssetsByTenantId(TenantId tenantId) { public void deleteAssetsByTenantId(TenantId tenantId) {
log.trace("Executing deleteAssetsByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteAssetsByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantAssetsRemover.removeEntities(tenantId, tenantId); tenantAssetsRemover.removeEntities(tenantId, tenantId);
} }
@Override @Override
public PageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findAssetsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findAssetsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -290,8 +289,8 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findAssetInfosByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findAssetInfosByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetInfosByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return assetDao.findAssetInfosByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -299,9 +298,9 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) { public PageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) {
log.trace("Executing findAssetsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink); log.trace("Executing findAssetsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetsByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink); return assetDao.findAssetsByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
} }
@ -309,9 +308,9 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) { public PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) {
log.trace("Executing findAssetInfosByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink); log.trace("Executing findAssetInfosByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetInfosByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink); return assetDao.findAssetInfosByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
} }
@ -319,9 +318,9 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId(TenantId tenantId, CustomerId customerId, AssetProfileId assetProfileId, PageLink pageLink) { public PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId(TenantId tenantId, CustomerId customerId, AssetProfileId assetProfileId, PageLink pageLink) {
log.trace("Executing findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId, tenantId [{}], customerId [{}], assetProfileId [{}], pageLink [{}]", tenantId, customerId, assetProfileId, pageLink); log.trace("Executing findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId, tenantId [{}], customerId [{}], assetProfileId [{}], pageLink [{}]", tenantId, customerId, assetProfileId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateId(assetProfileId, INCORRECT_ASSET_PROFILE_ID + assetProfileId); validateId(assetProfileId, id -> INCORRECT_ASSET_PROFILE_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId(tenantId.getId(), customerId.getId(), assetProfileId.getId(), pageLink); return assetDao.findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId(tenantId.getId(), customerId.getId(), assetProfileId.getId(), pageLink);
} }
@ -329,17 +328,17 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds) { public ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds) {
log.trace("Executing findAssetsByTenantIdAndCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], assetIds [{}]", tenantId, customerId, assetIds); log.trace("Executing findAssetsByTenantIdAndCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], assetIds [{}]", tenantId, customerId, assetIds);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateIds(assetIds, "Incorrect assetIds " + assetIds); validateIds(assetIds, ids -> "Incorrect assetIds " + ids);
return assetDao.findAssetsByTenantIdAndCustomerIdAndIdsAsync(tenantId.getId(), customerId.getId(), toUUIDs(assetIds)); return assetDao.findAssetsByTenantIdAndCustomerIdAndIdsAsync(tenantId.getId(), customerId.getId(), toUUIDs(assetIds));
} }
@Override @Override
public void unassignCustomerAssets(TenantId tenantId, CustomerId customerId) { public void unassignCustomerAssets(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerAssets, tenantId [{}], customerId [{}]", tenantId, customerId); log.trace("Executing unassignCustomerAssets, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
customerAssetsUnasigner.removeEntities(tenantId, customerId); customerAssetsUnasigner.removeEntities(tenantId, customerId);
} }
@ -371,7 +370,7 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId) { public ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId) {
log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return assetDao.findTenantAssetTypesAsync(tenantId.getId()); return assetDao.findTenantAssetTypesAsync(tenantId.getId());
} }
@ -420,8 +419,8 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<Asset> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) { public PageData<Asset> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) {
log.trace("Executing findAssetsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); log.trace("Executing findAssetsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); return assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
} }
@ -429,9 +428,9 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
@Override @Override
public PageData<Asset> findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink) { public PageData<Asset> findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink) {
log.trace("Executing findAssetsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}] pageLink [{}]", tenantId, edgeId, type, pageLink); log.trace("Executing findAssetsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}] pageLink [{}]", tenantId, edgeId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return assetDao.findAssetsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); return assetDao.findAssetsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink);
} }

6
dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeUtils.java

@ -28,12 +28,12 @@ public class AttributeUtils {
@Deprecated(since = "3.7.0") @Deprecated(since = "3.7.0")
public static void validate(EntityId id, String scope) { public static void validate(EntityId id, String scope) {
Validator.validateId(id.getId(), "Incorrect id " + id); Validator.validateId(id.getId(), uuid -> "Incorrect id " + uuid);
Validator.validateString(scope, "Incorrect scope " + scope); Validator.validateString(scope, sc -> "Incorrect scope " + sc);
} }
public static void validate(EntityId id, AttributeScope scope) { public static void validate(EntityId id, AttributeScope scope) {
Validator.validateId(id.getId(), "Incorrect id " + id); Validator.validateId(id.getId(), uuid -> "Incorrect id " + uuid);
Validator.checkNotNull(scope, "Incorrect scope " + scope); Validator.checkNotNull(scope, "Incorrect scope " + scope);
} }

8
dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java

@ -58,28 +58,28 @@ public class BaseAttributesService implements AttributesService {
@Override @Override
public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, String attributeKey) { public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, String attributeKey) {
validate(entityId, scope); validate(entityId, scope);
Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey); Validator.validateString(attributeKey, k -> "Incorrect attribute key " + k);
return Futures.immediateFuture(attributesDao.find(tenantId, entityId, AttributeScope.valueOf(scope), attributeKey)); return Futures.immediateFuture(attributesDao.find(tenantId, entityId, AttributeScope.valueOf(scope), attributeKey));
} }
@Override @Override
public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, String attributeKey) { public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, String attributeKey) {
validate(entityId, scope); validate(entityId, scope);
Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey); Validator.validateString(attributeKey, k -> "Incorrect attribute key " + k);
return Futures.immediateFuture(attributesDao.find(tenantId, entityId, scope, attributeKey)); return Futures.immediateFuture(attributesDao.find(tenantId, entityId, scope, attributeKey));
} }
@Override @Override
public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, Collection<String> attributeKeys) { public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, Collection<String> attributeKeys) {
validate(entityId, scope); validate(entityId, scope);
attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey)); attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, k -> "Incorrect attribute key " + k));
return Futures.immediateFuture(attributesDao.find(tenantId, entityId, AttributeScope.valueOf(scope), attributeKeys)); return Futures.immediateFuture(attributesDao.find(tenantId, entityId, AttributeScope.valueOf(scope), attributeKeys));
} }
@Override @Override
public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, Collection<String> attributeKeys) { public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, Collection<String> attributeKeys) {
validate(entityId, scope); validate(entityId, scope);
attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey)); attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, k -> "Incorrect attribute key " + k));
return Futures.immediateFuture(attributesDao.find(tenantId, entityId, scope, attributeKeys)); return Futures.immediateFuture(attributesDao.find(tenantId, entityId, scope, attributeKeys));
} }

4
dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java

@ -117,7 +117,7 @@ public class CachedAttributesService implements AttributesService {
@Override @Override
public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, String attributeKey) { public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, String attributeKey) {
validate(entityId, scope); validate(entityId, scope);
Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey); Validator.validateString(attributeKey, k -> "Incorrect attribute key " + k);
return cacheExecutor.submit(() -> { return cacheExecutor.submit(() -> {
AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, attributeKey); AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, attributeKey);
@ -152,7 +152,7 @@ public class CachedAttributesService implements AttributesService {
public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, final Collection<String> attributeKeysNonUnique) { public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, AttributeScope scope, final Collection<String> attributeKeysNonUnique) {
validate(entityId, scope); validate(entityId, scope);
final var attributeKeys = new LinkedHashSet<>(attributeKeysNonUnique); // deduplicate the attributes final var attributeKeys = new LinkedHashSet<>(attributeKeysNonUnique); // deduplicate the attributes
attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey)); attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, k ->"Incorrect attribute key " + k));
//CacheExecutor for Redis or DirectExecutor for local Caffeine //CacheExecutor for Redis or DirectExecutor for local Caffeine
return Futures.transformAsync(cacheExecutor.submit(() -> findCachedAttributes(entityId, scope, attributeKeys)), return Futures.transformAsync(cacheExecutor.submit(() -> findCachedAttributes(entityId, scope, attributeKeys)),

14
dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java

@ -85,31 +85,31 @@ public class AuditLogServiceImpl implements AuditLogService {
@Override @Override
public PageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, List<ActionType> actionTypes, TimePageLink pageLink) { public PageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, List<ActionType> actionTypes, TimePageLink pageLink) {
log.trace("Executing findAuditLogsByTenantIdAndCustomerId [{}], [{}], [{}]", tenantId, customerId, pageLink); log.trace("Executing findAuditLogsByTenantIdAndCustomerId [{}], [{}], [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, "Incorrect customerId " + customerId); validateId(customerId, id -> "Incorrect customerId " + id);
return auditLogDao.findAuditLogsByTenantIdAndCustomerId(tenantId.getId(), customerId, actionTypes, pageLink); return auditLogDao.findAuditLogsByTenantIdAndCustomerId(tenantId.getId(), customerId, actionTypes, pageLink);
} }
@Override @Override
public PageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, List<ActionType> actionTypes, TimePageLink pageLink) { public PageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, List<ActionType> actionTypes, TimePageLink pageLink) {
log.trace("Executing findAuditLogsByTenantIdAndUserId [{}], [{}], [{}]", tenantId, userId, pageLink); log.trace("Executing findAuditLogsByTenantIdAndUserId [{}], [{}], [{}]", tenantId, userId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(userId, "Incorrect userId" + userId); validateId(userId, id -> "Incorrect userId" + id);
return auditLogDao.findAuditLogsByTenantIdAndUserId(tenantId.getId(), userId, actionTypes, pageLink); return auditLogDao.findAuditLogsByTenantIdAndUserId(tenantId.getId(), userId, actionTypes, pageLink);
} }
@Override @Override
public PageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, List<ActionType> actionTypes, TimePageLink pageLink) { public PageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, List<ActionType> actionTypes, TimePageLink pageLink) {
log.trace("Executing findAuditLogsByTenantIdAndEntityId [{}], [{}], [{}]", tenantId, entityId, pageLink); log.trace("Executing findAuditLogsByTenantIdAndEntityId [{}], [{}], [{}]", tenantId, entityId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateEntityId(entityId, INCORRECT_TENANT_ID + entityId); validateEntityId(entityId, id -> "Incorrect entityId" + id);
return auditLogDao.findAuditLogsByTenantIdAndEntityId(tenantId.getId(), entityId, actionTypes, pageLink); return auditLogDao.findAuditLogsByTenantIdAndEntityId(tenantId.getId(), entityId, actionTypes, pageLink);
} }
@Override @Override
public PageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, List<ActionType> actionTypes, TimePageLink pageLink) { public PageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, List<ActionType> actionTypes, TimePageLink pageLink) {
log.trace("Executing findAuditLogs [{}]", pageLink); log.trace("Executing findAuditLogs [{}]", pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return auditLogDao.findAuditLogsByTenantId(tenantId.getId(), actionTypes, pageLink); return auditLogDao.findAuditLogsByTenantId(tenantId.getId(), actionTypes, pageLink);
} }

14
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java

@ -84,21 +84,21 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Override @Override
public Customer findCustomerById(TenantId tenantId, CustomerId customerId) { public Customer findCustomerById(TenantId tenantId, CustomerId customerId) {
log.trace("Executing findCustomerById [{}]", customerId); log.trace("Executing findCustomerById [{}]", customerId);
Validator.validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); Validator.validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
return customerDao.findById(tenantId, customerId.getId()); return customerDao.findById(tenantId, customerId.getId());
} }
@Override @Override
public Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title) { public Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title) {
log.trace("Executing findCustomerByTenantIdAndTitle [{}] [{}]", tenantId, title); log.trace("Executing findCustomerByTenantIdAndTitle [{}] [{}]", tenantId, title);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return customerDao.findCustomersByTenantIdAndTitle(tenantId.getId(), title); return customerDao.findCustomersByTenantIdAndTitle(tenantId.getId(), title);
} }
@Override @Override
public ListenableFuture<Customer> findCustomerByIdAsync(TenantId tenantId, CustomerId customerId) { public ListenableFuture<Customer> findCustomerByIdAsync(TenantId tenantId, CustomerId customerId) {
log.trace("Executing findCustomerByIdAsync [{}]", customerId); log.trace("Executing findCustomerByIdAsync [{}]", customerId);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
return customerDao.findByIdAsync(tenantId, customerId.getId()); return customerDao.findByIdAsync(tenantId, customerId.getId());
} }
@ -126,7 +126,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Transactional @Transactional
public void deleteCustomer(TenantId tenantId, CustomerId customerId) { public void deleteCustomer(TenantId tenantId, CustomerId customerId) {
log.trace("Executing deleteCustomer [{}]", customerId); log.trace("Executing deleteCustomer [{}]", customerId);
Validator.validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); Validator.validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
Customer customer = findCustomerById(tenantId, customerId); Customer customer = findCustomerById(tenantId, customerId);
if (customer == null) { if (customer == null) {
throw new IncorrectParameterException("Unable to delete non-existent customer."); throw new IncorrectParameterException("Unable to delete non-existent customer.");
@ -147,7 +147,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Override @Override
public Customer findOrCreatePublicCustomer(TenantId tenantId) { public Customer findOrCreatePublicCustomer(TenantId tenantId) {
log.trace("Executing findOrCreatePublicCustomer, tenantId [{}]", tenantId); log.trace("Executing findOrCreatePublicCustomer, tenantId [{}]", tenantId);
Validator.validateId(tenantId, INCORRECT_CUSTOMER_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_CUSTOMER_ID + id);
Optional<Customer> publicCustomerOpt = customerDao.findCustomersByTenantIdAndTitle(tenantId.getId(), PUBLIC_CUSTOMER_TITLE); Optional<Customer> publicCustomerOpt = customerDao.findCustomersByTenantIdAndTitle(tenantId.getId(), PUBLIC_CUSTOMER_TITLE);
if (publicCustomerOpt.isPresent()) { if (publicCustomerOpt.isPresent()) {
return publicCustomerOpt.get(); return publicCustomerOpt.get();
@ -169,7 +169,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Override @Override
public PageData<Customer> findCustomersByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<Customer> findCustomersByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findCustomersByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findCustomersByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); Validator.validateId(tenantId, id -> "Incorrect tenantId " + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return customerDao.findCustomersByTenantId(tenantId.getId(), pageLink); return customerDao.findCustomersByTenantId(tenantId.getId(), pageLink);
} }
@ -177,7 +177,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Override @Override
public void deleteCustomersByTenantId(TenantId tenantId) { public void deleteCustomersByTenantId(TenantId tenantId) {
log.trace("Executing deleteCustomersByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteCustomersByTenantId, tenantId [{}]", tenantId);
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); Validator.validateId(tenantId, id -> "Incorrect tenantId " + id);
customersByTenantRemover.removeEntities(tenantId, tenantId); customersByTenantRemover.removeEntities(tenantId, tenantId);
} }

32
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -110,21 +110,21 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId) { public Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardById [{}]", dashboardId); log.trace("Executing findDashboardById [{}]", dashboardId);
Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); Validator.validateId(dashboardId, id -> INCORRECT_DASHBOARD_ID + id);
return dashboardDao.findById(tenantId, dashboardId.getId()); return dashboardDao.findById(tenantId, dashboardId.getId());
} }
@Override @Override
public ListenableFuture<Dashboard> findDashboardByIdAsync(TenantId tenantId, DashboardId dashboardId) { public ListenableFuture<Dashboard> findDashboardByIdAsync(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardByIdAsync [{}]", dashboardId); log.trace("Executing findDashboardByIdAsync [{}]", dashboardId);
validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); validateId(dashboardId, id -> INCORRECT_DASHBOARD_ID + id);
return dashboardDao.findByIdAsync(tenantId, dashboardId.getId()); return dashboardDao.findByIdAsync(tenantId, dashboardId.getId());
} }
@Override @Override
public DashboardInfo findDashboardInfoById(TenantId tenantId, DashboardId dashboardId) { public DashboardInfo findDashboardInfoById(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardInfoById [{}]", dashboardId); log.trace("Executing findDashboardInfoById [{}]", dashboardId);
Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); Validator.validateId(dashboardId, id -> INCORRECT_DASHBOARD_ID + id);
return dashboardInfoDao.findById(tenantId, dashboardId.getId()); return dashboardInfoDao.findById(tenantId, dashboardId.getId());
} }
@ -137,7 +137,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId) { public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId); log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); validateId(dashboardId, id -> INCORRECT_DASHBOARD_ID + id);
return dashboardInfoDao.findByIdAsync(tenantId, dashboardId.getId()); return dashboardInfoDao.findByIdAsync(tenantId, dashboardId.getId());
} }
@ -229,7 +229,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Transactional @Transactional
public void deleteDashboard(TenantId tenantId, DashboardId dashboardId) { public void deleteDashboard(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing deleteDashboard [{}]", dashboardId); log.trace("Executing deleteDashboard [{}]", dashboardId);
Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); Validator.validateId(dashboardId, id -> INCORRECT_DASHBOARD_ID + id);
deleteEntityRelations(tenantId, dashboardId); deleteEntityRelations(tenantId, dashboardId);
try { try {
dashboardDao.removeById(tenantId, dashboardId.getId()); dashboardDao.removeById(tenantId, dashboardId.getId());
@ -249,7 +249,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return dashboardInfoDao.findDashboardsByTenantId(tenantId.getId(), pageLink); return dashboardInfoDao.findDashboardsByTenantId(tenantId.getId(), pageLink);
} }
@ -257,7 +257,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public PageData<DashboardInfo> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<DashboardInfo> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findMobileDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findMobileDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return dashboardInfoDao.findMobileDashboardsByTenantId(tenantId.getId(), pageLink); return dashboardInfoDao.findMobileDashboardsByTenantId(tenantId.getId(), pageLink);
} }
@ -265,15 +265,15 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public void deleteDashboardsByTenantId(TenantId tenantId) { public void deleteDashboardsByTenantId(TenantId tenantId) {
log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantDashboardsRemover.removeEntities(tenantId, tenantId); tenantDashboardsRemover.removeEntities(tenantId, tenantId);
} }
@Override @Override
public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validateId(customerId, "Incorrect customerId " + customerId); Validator.validateId(customerId, id -> "Incorrect customerId " + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -281,8 +281,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findMobileDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findMobileDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validateId(customerId, "Incorrect customerId " + customerId); Validator.validateId(customerId, id -> "Incorrect customerId " + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return dashboardInfoDao.findMobileDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return dashboardInfoDao.findMobileDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -290,7 +290,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) { public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId); log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId);
Validator.validateId(customerId, "Incorrect customerId " + customerId); Validator.validateId(customerId, id -> "Incorrect customerId " + id);
Customer customer = customerDao.findById(tenantId, customerId.getId()); Customer customer = customerDao.findById(tenantId, customerId.getId());
if (customer == null) { if (customer == null) {
throw new DataValidationException("Can't unassign dashboards from non-existent customer!"); throw new DataValidationException("Can't unassign dashboards from non-existent customer!");
@ -301,7 +301,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public void updateCustomerDashboards(TenantId tenantId, CustomerId customerId) { public void updateCustomerDashboards(TenantId tenantId, CustomerId customerId) {
log.trace("Executing updateCustomerDashboards, customerId [{}]", customerId); log.trace("Executing updateCustomerDashboards, customerId [{}]", customerId);
Validator.validateId(customerId, "Incorrect customerId " + customerId); Validator.validateId(customerId, id -> "Incorrect customerId " + id);
Customer customer = customerDao.findById(tenantId, customerId.getId()); Customer customer = customerDao.findById(tenantId, customerId.getId());
if (customer == null) { if (customer == null) {
throw new DataValidationException("Can't update dashboards for non-existent customer!"); throw new DataValidationException("Can't update dashboards for non-existent customer!");
@ -351,8 +351,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override @Override
public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) { public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) {
log.trace("Executing findDashboardsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); log.trace("Executing findDashboardsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validateId(edgeId, INCORRECT_EDGE_ID + edgeId); Validator.validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return dashboardInfoDao.findDashboardsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); return dashboardInfoDao.findDashboardsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
} }

2
dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java

@ -88,7 +88,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
public JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException { public JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException {
DeviceId deviceId = device.getId(); DeviceId deviceId = device.getId();
log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, id -> INCORRECT_DEVICE_ID + id);
DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId);
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());

4
dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java

@ -72,14 +72,14 @@ public class DeviceCredentialsServiceImpl extends AbstractCachedEntityService<St
@Override @Override
public DeviceCredentials findDeviceCredentialsByDeviceId(TenantId tenantId, DeviceId deviceId) { public DeviceCredentials findDeviceCredentialsByDeviceId(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceCredentialsByDeviceId [{}]", deviceId); log.trace("Executing findDeviceCredentialsByDeviceId [{}]", deviceId);
validateId(deviceId, "Incorrect deviceId " + deviceId); validateId(deviceId, id -> "Incorrect deviceId " + id);
return deviceCredentialsDao.findByDeviceId(tenantId, deviceId.getId()); return deviceCredentialsDao.findByDeviceId(tenantId, deviceId.getId());
} }
@Override @Override
public DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId) { public DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId) {
log.trace("Executing findDeviceCredentialsByCredentialsId [{}]", credentialsId); log.trace("Executing findDeviceCredentialsByCredentialsId [{}]", credentialsId);
validateString(credentialsId, "Incorrect credentialsId " + credentialsId); validateString(credentialsId, id -> "Incorrect credentialsId " + id);
return cache.getAndPutInTransaction(credentialsId, return cache.getAndPutInTransaction(credentialsId,
() -> deviceCredentialsDao.findByCredentialsId(TenantId.SYS_TENANT_ID, credentialsId), () -> deviceCredentialsDao.findByCredentialsId(TenantId.SYS_TENANT_ID, credentialsId),
true); // caching null values is essential for permanently invalid requests true); // caching null values is essential for permanently invalid requests

26
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -126,7 +126,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId, boolean putInCache) { public DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId, boolean putInCache) {
log.trace("Executing findDeviceProfileById [{}]", deviceProfileId); log.trace("Executing findDeviceProfileById [{}]", deviceProfileId);
validateId(deviceProfileId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromId(deviceProfileId), return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromId(deviceProfileId),
() -> deviceProfileDao.findById(tenantId, deviceProfileId.getId()), true, putInCache); () -> deviceProfileDao.findById(tenantId, deviceProfileId.getId()), true, putInCache);
} }
@ -139,7 +139,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName, boolean putInCache) { public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName, boolean putInCache) {
log.trace("Executing findDeviceProfileByName [{}][{}]", tenantId, profileName); log.trace("Executing findDeviceProfileByName [{}][{}]", tenantId, profileName);
validateString(profileName, INCORRECT_DEVICE_PROFILE_NAME + profileName); validateString(profileName, pn -> INCORRECT_DEVICE_PROFILE_NAME + pn);
return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromName(tenantId, profileName), return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromName(tenantId, profileName),
() -> deviceProfileDao.findByName(tenantId, profileName), true, putInCache); () -> deviceProfileDao.findByName(tenantId, profileName), true, putInCache);
} }
@ -147,7 +147,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public DeviceProfile findDeviceProfileByProvisionDeviceKey(String provisionDeviceKey) { public DeviceProfile findDeviceProfileByProvisionDeviceKey(String provisionDeviceKey) {
log.trace("Executing findDeviceProfileByProvisionDeviceKey provisionKey [{}]", provisionDeviceKey); log.trace("Executing findDeviceProfileByProvisionDeviceKey provisionKey [{}]", provisionDeviceKey);
validateString(provisionDeviceKey, INCORRECT_PROVISION_DEVICE_KEY + provisionDeviceKey); validateString(provisionDeviceKey, dk -> INCORRECT_PROVISION_DEVICE_KEY + dk);
return cache.getAndPutInTransaction(DeviceProfileCacheKey.fromProvisionDeviceKey(provisionDeviceKey), return cache.getAndPutInTransaction(DeviceProfileCacheKey.fromProvisionDeviceKey(provisionDeviceKey),
() -> deviceProfileDao.findByProvisionDeviceKey(provisionDeviceKey), false); () -> deviceProfileDao.findByProvisionDeviceKey(provisionDeviceKey), false);
} }
@ -155,7 +155,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) { public DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) {
log.trace("Executing findDeviceProfileById [{}]", deviceProfileId); log.trace("Executing findDeviceProfileById [{}]", deviceProfileId);
validateId(deviceProfileId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
return toDeviceProfileInfo(findDeviceProfileById(tenantId, deviceProfileId)); return toDeviceProfileInfo(findDeviceProfileById(tenantId, deviceProfileId));
} }
@ -222,7 +222,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Transactional @Transactional
public void deleteDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { public void deleteDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) {
log.trace("Executing deleteDeviceProfile [{}]", deviceProfileId); log.trace("Executing deleteDeviceProfile [{}]", deviceProfileId);
validateId(deviceProfileId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
DeviceProfile deviceProfile = deviceProfileDao.findById(tenantId, deviceProfileId.getId()); DeviceProfile deviceProfile = deviceProfileDao.findById(tenantId, deviceProfileId.getId());
if (deviceProfile != null && deviceProfile.isDefault()) { if (deviceProfile != null && deviceProfile.isDefault()) {
throw new DataValidationException("Deletion of Default Device Profile is prohibited!"); throw new DataValidationException("Deletion of Default Device Profile is prohibited!");
@ -252,7 +252,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public PageData<DeviceProfile> findDeviceProfiles(TenantId tenantId, PageLink pageLink) { public PageData<DeviceProfile> findDeviceProfiles(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findDeviceProfiles tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findDeviceProfiles tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return deviceProfileDao.findDeviceProfiles(tenantId, pageLink); return deviceProfileDao.findDeviceProfiles(tenantId, pageLink);
} }
@ -260,7 +260,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public PageData<DeviceProfileInfo> findDeviceProfileInfos(TenantId tenantId, PageLink pageLink, String transportType) { public PageData<DeviceProfileInfo> findDeviceProfileInfos(TenantId tenantId, PageLink pageLink, String transportType) {
log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink, transportType); return deviceProfileDao.findDeviceProfileInfos(tenantId, pageLink, transportType);
} }
@ -290,7 +290,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
} }
private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) { private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) {
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
DeviceProfile deviceProfile = new DeviceProfile(); DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setTenantId(tenantId); deviceProfile.setTenantId(tenantId);
deviceProfile.setDefault(defaultProfile); deviceProfile.setDefault(defaultProfile);
@ -313,7 +313,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public DeviceProfile findDefaultDeviceProfile(TenantId tenantId) { public DeviceProfile findDefaultDeviceProfile(TenantId tenantId) {
log.trace("Executing findDefaultDeviceProfile tenantId [{}]", tenantId); log.trace("Executing findDefaultDeviceProfile tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return cache.getAndPutInTransaction(DeviceProfileCacheKey.defaultProfile(tenantId), return cache.getAndPutInTransaction(DeviceProfileCacheKey.defaultProfile(tenantId),
() -> deviceProfileDao.findDefaultDeviceProfile(tenantId), true); () -> deviceProfileDao.findDefaultDeviceProfile(tenantId), true);
} }
@ -321,14 +321,14 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId) { public DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId) {
log.trace("Executing findDefaultDeviceProfileInfo tenantId [{}]", tenantId); log.trace("Executing findDefaultDeviceProfileInfo tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return toDeviceProfileInfo(findDefaultDeviceProfile(tenantId)); return toDeviceProfileInfo(findDefaultDeviceProfile(tenantId));
} }
@Override @Override
public boolean setDefaultDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) { public boolean setDefaultDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId) {
log.trace("Executing setDefaultDeviceProfile [{}]", deviceProfileId); log.trace("Executing setDefaultDeviceProfile [{}]", deviceProfileId);
validateId(deviceProfileId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
DeviceProfile deviceProfile = deviceProfileDao.findById(tenantId, deviceProfileId.getId()); DeviceProfile deviceProfile = deviceProfileDao.findById(tenantId, deviceProfileId.getId());
if (!deviceProfile.isDefault()) { if (!deviceProfile.isDefault()) {
deviceProfile.setDefault(true); deviceProfile.setDefault(true);
@ -354,7 +354,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public void deleteDeviceProfilesByTenantId(TenantId tenantId) { public void deleteDeviceProfilesByTenantId(TenantId tenantId) {
log.trace("Executing deleteDeviceProfilesByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteDeviceProfilesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantDeviceProfilesRemover.removeEntities(tenantId, tenantId); tenantDeviceProfilesRemover.removeEntities(tenantId, tenantId);
} }
@ -377,7 +377,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Override @Override
public List<EntityInfo> findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) { public List<EntityInfo> findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) {
log.trace("Executing findDeviceProfileNamesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findDeviceProfileNamesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return deviceProfileDao.findTenantDeviceProfileNames(tenantId.getId(), activeOnly) return deviceProfileDao.findTenantDeviceProfileNames(tenantId.getId(), activeOnly)
.stream().sorted(Comparator.comparing(EntityInfo::getName)) .stream().sorted(Comparator.comparing(EntityInfo::getName))
.collect(Collectors.toList()); .collect(Collectors.toList());

68
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -126,14 +126,14 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceInfoById [{}]", deviceId); log.trace("Executing findDeviceInfoById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, id -> INCORRECT_DEVICE_ID + id);
return deviceDao.findDeviceInfoById(tenantId, deviceId.getId()); return deviceDao.findDeviceInfoById(tenantId, deviceId.getId());
} }
@Override @Override
public Device findDeviceById(TenantId tenantId, DeviceId deviceId) { public Device findDeviceById(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceById [{}]", deviceId); log.trace("Executing findDeviceById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, id -> INCORRECT_DEVICE_ID + id);
if (TenantId.SYS_TENANT_ID.equals(tenantId)) { if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
return cache.getAndPutInTransaction(new DeviceCacheKey(deviceId), return cache.getAndPutInTransaction(new DeviceCacheKey(deviceId),
() -> deviceDao.findById(tenantId, deviceId.getId()), true); () -> deviceDao.findById(tenantId, deviceId.getId()), true);
@ -146,7 +146,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) { public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceById [{}]", deviceId); log.trace("Executing findDeviceById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, id -> INCORRECT_DEVICE_ID + id);
if (TenantId.SYS_TENANT_ID.equals(tenantId)) { if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
return deviceDao.findByIdAsync(tenantId, deviceId.getId()); return deviceDao.findByIdAsync(tenantId, deviceId.getId());
} else { } else {
@ -157,7 +157,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public Device findDeviceByTenantIdAndName(TenantId tenantId, String name) { public Device findDeviceByTenantIdAndName(TenantId tenantId, String name) {
log.trace("Executing findDeviceByTenantIdAndName [{}][{}]", tenantId, name); log.trace("Executing findDeviceByTenantIdAndName [{}][{}]", tenantId, name);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return cache.getAndPutInTransaction(new DeviceCacheKey(tenantId, name), return cache.getAndPutInTransaction(new DeviceCacheKey(tenantId, name),
() -> deviceDao.findDeviceByTenantIdAndName(tenantId.getId(), name).orElse(null), true); () -> deviceDao.findDeviceByTenantIdAndName(tenantId.getId(), name).orElse(null), true);
} }
@ -321,7 +321,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Transactional @Transactional
@Override @Override
public void deleteDevice(final TenantId tenantId, final DeviceId deviceId) { public void deleteDevice(final TenantId tenantId, final DeviceId deviceId) {
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, id -> INCORRECT_DEVICE_ID + id);
if (entityViewService.existsByTenantIdAndEntityId(tenantId, deviceId)) { if (entityViewService.existsByTenantIdAndEntityId(tenantId, deviceId)) {
throw new DataValidationException("Can't delete device that has entity views!"); throw new DataValidationException("Can't delete device that has entity views!");
} }
@ -347,7 +347,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public PageData<Device> findDevicesByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<Device> findDevicesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findDevicesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findDevicesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id ->INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink); return deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink);
} }
@ -359,7 +359,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
if (filter == null) { if (filter == null) {
throw new IncorrectParameterException("Filter is empty!"); throw new IncorrectParameterException("Filter is empty!");
} }
validateId(filter.getTenantId(), INCORRECT_TENANT_ID + filter.getTenantId()); validateId(filter.getTenantId(), id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDeviceInfosByFilter(filter, pageLink); return deviceDao.findDeviceInfosByFilter(filter, pageLink);
@ -375,8 +375,8 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public PageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { public PageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndType(tenantId.getId(), type, pageLink); return deviceDao.findDevicesByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@ -388,8 +388,8 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
PageLink pageLink) { PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyOtaPackage, tenantId [{}], deviceProfileId [{}], type [{}], pageLink [{}]", log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyOtaPackage, tenantId [{}], deviceProfileId [{}], type [{}], pageLink [{}]",
tenantId, deviceProfileId, type, pageLink); tenantId, deviceProfileId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(tenantId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndTypeAndEmptyOtaPackage(tenantId.getId(), deviceProfileId.getId(), type, pageLink); return deviceDao.findDevicesByTenantIdAndTypeAndEmptyOtaPackage(tenantId.getId(), deviceProfileId.getId(), type, pageLink);
} }
@ -397,30 +397,30 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType type) { public Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType type) {
log.trace("Executing countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage, tenantId [{}], deviceProfileId [{}], type [{}]", tenantId, deviceProfileId, type); log.trace("Executing countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage, tenantId [{}], deviceProfileId [{}], type [{}]", tenantId, deviceProfileId, type);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(tenantId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId); validateId(deviceProfileId, id -> INCORRECT_DEVICE_PROFILE_ID + id);
return deviceDao.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(tenantId.getId(), deviceProfileId.getId(), type); return deviceDao.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(tenantId.getId(), deviceProfileId.getId(), type);
} }
@Override @Override
public ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds) { public ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds) {
log.trace("Executing findDevicesByTenantIdAndIdsAsync, tenantId [{}], deviceIds [{}]", tenantId, deviceIds); log.trace("Executing findDevicesByTenantIdAndIdsAsync, tenantId [{}], deviceIds [{}]", tenantId, deviceIds);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(deviceIds, "Incorrect deviceIds " + deviceIds); validateIds(deviceIds, ids -> "Incorrect deviceIds " + ids);
return deviceDao.findDevicesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(deviceIds)); return deviceDao.findDevicesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(deviceIds));
} }
@Override @Override
public List<Device> findDevicesByIds(List<DeviceId> deviceIds) { public List<Device> findDevicesByIds(List<DeviceId> deviceIds) {
log.trace("Executing findDevicesByIdsAsync, deviceIds [{}]", deviceIds); log.trace("Executing findDevicesByIdsAsync, deviceIds [{}]", deviceIds);
validateIds(deviceIds, "Incorrect deviceIds " + deviceIds); validateIds(deviceIds, ids-> "Incorrect deviceIds " + ids);
return deviceDao.findDevicesByIds(toUUIDs(deviceIds)); return deviceDao.findDevicesByIds(toUUIDs(deviceIds));
} }
@Override @Override
public ListenableFuture<List<Device>> findDevicesByIdsAsync(List<DeviceId> deviceIds) { public ListenableFuture<List<Device>> findDevicesByIdsAsync(List<DeviceId> deviceIds) {
log.trace("Executing findDevicesByIdsAsync, deviceIds [{}]", deviceIds); log.trace("Executing findDevicesByIdsAsync, deviceIds [{}]", deviceIds);
validateIds(deviceIds, "Incorrect deviceIds " + deviceIds); validateIds(deviceIds, ids-> "Incorrect deviceIds " + ids);
return deviceDao.findDevicesByIdsAsync(toUUIDs(deviceIds)); return deviceDao.findDevicesByIdsAsync(toUUIDs(deviceIds));
} }
@ -428,15 +428,15 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public void deleteDevicesByTenantId(TenantId tenantId) { public void deleteDevicesByTenantId(TenantId tenantId) {
log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantDevicesRemover.removeEntities(tenantId, tenantId); tenantDevicesRemover.removeEntities(tenantId, tenantId);
} }
@Override @Override
public PageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findDevicesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -444,9 +444,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public PageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) { public PageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink); log.trace("Executing findDevicesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink); return deviceDao.findDevicesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
} }
@ -454,9 +454,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds) { public ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds) {
log.trace("Executing findDevicesByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], deviceIds [{}]", tenantId, customerId, deviceIds); log.trace("Executing findDevicesByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], deviceIds [{}]", tenantId, customerId, deviceIds);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateIds(deviceIds, "Incorrect deviceIds " + deviceIds); validateIds(deviceIds, ids -> "Incorrect deviceIds " + ids);
return deviceDao.findDevicesByTenantIdCustomerIdAndIdsAsync(tenantId.getId(), return deviceDao.findDevicesByTenantIdCustomerIdAndIdsAsync(tenantId.getId(),
customerId.getId(), toUUIDs(deviceIds)); customerId.getId(), toUUIDs(deviceIds));
} }
@ -464,8 +464,8 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public void unassignCustomerDevices(TenantId tenantId, CustomerId customerId) { public void unassignCustomerDevices(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerDevices, tenantId [{}], customerId [{}]", tenantId, customerId); log.trace("Executing unassignCustomerDevices, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
customerDevicesRemover.removeEntities(tenantId, customerId); customerDevicesRemover.removeEntities(tenantId, customerId);
} }
@ -491,7 +491,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId) { public ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId) {
log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return deviceDao.findTenantDeviceTypesAsync(tenantId.getId()); return deviceDao.findTenantDeviceTypesAsync(tenantId.getId());
} }
@ -627,8 +627,8 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public PageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) { public PageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); log.trace("Executing findDevicesByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); return deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
} }
@ -636,9 +636,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override @Override
public PageData<Device> findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink) { public PageData<Device> findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}] pageLink [{}]", tenantId, edgeId, type, pageLink); log.trace("Executing findDevicesByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}] pageLink [{}]", tenantId, edgeId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); return deviceDao.findDevicesByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink);
} }

64
dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java

@ -138,28 +138,28 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) { public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) {
log.trace("Executing findEdgeById [{}]", edgeId); log.trace("Executing findEdgeById [{}]", edgeId);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
return edgeDao.findById(tenantId, edgeId.getId()); return edgeDao.findById(tenantId, edgeId.getId());
} }
@Override @Override
public EdgeInfo findEdgeInfoById(TenantId tenantId, EdgeId edgeId) { public EdgeInfo findEdgeInfoById(TenantId tenantId, EdgeId edgeId) {
log.trace("Executing findEdgeInfoById [{}]", edgeId); log.trace("Executing findEdgeInfoById [{}]", edgeId);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
return edgeDao.findEdgeInfoById(tenantId, edgeId.getId()); return edgeDao.findEdgeInfoById(tenantId, edgeId.getId());
} }
@Override @Override
public ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) { public ListenableFuture<Edge> findEdgeByIdAsync(TenantId tenantId, EdgeId edgeId) {
log.trace("Executing findEdgeById [{}]", edgeId); log.trace("Executing findEdgeById [{}]", edgeId);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
return edgeDao.findByIdAsync(tenantId, edgeId.getId()); return edgeDao.findByIdAsync(tenantId, edgeId.getId());
} }
@Override @Override
public Edge findEdgeByTenantIdAndName(TenantId tenantId, String name) { public Edge findEdgeByTenantIdAndName(TenantId tenantId, String name) {
log.trace("Executing findEdgeByTenantIdAndName [{}][{}]", tenantId, name); log.trace("Executing findEdgeByTenantIdAndName [{}][{}]", tenantId, name);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return cache.getAndPutInTransaction(new EdgeCacheKey(tenantId, name), return cache.getAndPutInTransaction(new EdgeCacheKey(tenantId, name),
() -> edgeDao.findEdgeByTenantIdAndName(tenantId.getId(), name) () -> edgeDao.findEdgeByTenantIdAndName(tenantId.getId(), name)
.orElse(null), true); .orElse(null), true);
@ -221,7 +221,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Transactional @Transactional
public void deleteEdge(TenantId tenantId, EdgeId edgeId) { public void deleteEdge(TenantId tenantId, EdgeId edgeId) {
log.trace("Executing deleteEdge [{}]", edgeId); log.trace("Executing deleteEdge [{}]", edgeId);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
Edge edge = edgeDao.findById(tenantId, edgeId.getId()); Edge edge = edgeDao.findById(tenantId, edgeId.getId());
@ -236,7 +236,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<Edge> findEdgesByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<Edge> findEdgesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgesByTenantId(tenantId.getId(), pageLink); return edgeDao.findEdgesByTenantId(tenantId.getId(), pageLink);
} }
@ -244,8 +244,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<Edge> findEdgesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { public PageData<Edge> findEdgesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findEdgesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); log.trace("Executing findEdgesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgesByTenantIdAndType(tenantId.getId(), type, pageLink); return edgeDao.findEdgesByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@ -253,8 +253,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<EdgeInfo> findEdgeInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { public PageData<EdgeInfo> findEdgeInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findEdgeInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); log.trace("Executing findEdgeInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgeInfosByTenantIdAndType(tenantId.getId(), type, pageLink); return edgeDao.findEdgeInfosByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@ -262,7 +262,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<EdgeInfo> findEdgeInfosByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<EdgeInfo> findEdgeInfosByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findEdgeInfosByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findEdgeInfosByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgeInfosByTenantId(tenantId.getId(), pageLink); return edgeDao.findEdgeInfosByTenantId(tenantId.getId(), pageLink);
} }
@ -270,23 +270,23 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List<EdgeId> edgeIds) { public ListenableFuture<List<Edge>> findEdgesByTenantIdAndIdsAsync(TenantId tenantId, List<EdgeId> edgeIds) {
log.trace("Executing findEdgesByTenantIdAndIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds); log.trace("Executing findEdgesByTenantIdAndIdsAsync, tenantId [{}], edgeIds [{}]", tenantId, edgeIds);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(edgeIds, "Incorrect edgeIds " + edgeIds); validateIds(edgeIds, ids -> "Incorrect edgeIds " + ids);
return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds)); return edgeDao.findEdgesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(edgeIds));
} }
@Override @Override
public void deleteEdgesByTenantId(TenantId tenantId) { public void deleteEdgesByTenantId(TenantId tenantId) {
log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteEdgesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantEdgesRemover.removeEntities(tenantId, tenantId); tenantEdgesRemover.removeEntities(tenantId, tenantId);
} }
@Override @Override
public PageData<Edge> findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<Edge> findEdgesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findEdgesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findEdgesByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return edgeDao.findEdgesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -294,9 +294,9 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<Edge> findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) { public PageData<Edge> findEdgesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) {
log.trace("Executing findEdgesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink); log.trace("Executing findEdgesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink); return edgeDao.findEdgesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
} }
@ -304,8 +304,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<EdgeInfo> findEdgeInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<EdgeInfo> findEdgeInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findEdgeInfosByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); log.trace("Executing findEdgeInfosByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgeInfosByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return edgeDao.findEdgeInfosByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@ -313,9 +313,9 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<EdgeInfo> findEdgeInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) { public PageData<EdgeInfo> findEdgeInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) {
log.trace("Executing findEdgeInfosByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink); log.trace("Executing findEdgeInfosByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgeInfosByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink); return edgeDao.findEdgeInfosByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
} }
@ -323,9 +323,9 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<EdgeId> edgeIds) { public ListenableFuture<List<Edge>> findEdgesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<EdgeId> edgeIds) {
log.trace("Executing findEdgesByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], edgeIds [{}]", tenantId, customerId, edgeIds); log.trace("Executing findEdgesByTenantIdCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], edgeIds [{}]", tenantId, customerId, edgeIds);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateIds(edgeIds, "Incorrect edgeIds " + edgeIds); validateIds(edgeIds, ids -> "Incorrect edgeIds " + ids);
return edgeDao.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId.getId(), return edgeDao.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId.getId(),
customerId.getId(), toUUIDs(edgeIds)); customerId.getId(), toUUIDs(edgeIds));
} }
@ -333,8 +333,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public void unassignCustomerEdges(TenantId tenantId, CustomerId customerId) { public void unassignCustomerEdges(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerEdges, tenantId [{}], customerId [{}]", tenantId, customerId); log.trace("Executing unassignCustomerEdges, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
customerEdgeUnassigner.removeEntities(tenantId, customerId); customerEdgeUnassigner.removeEntities(tenantId, customerId);
} }
@ -370,7 +370,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId) { public ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId) {
log.trace("Executing findEdgeTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findEdgeTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
ListenableFuture<List<EntitySubtype>> tenantEdgeTypes = edgeDao.findTenantEdgeTypesAsync(tenantId.getId()); ListenableFuture<List<EntitySubtype>> tenantEdgeTypes = edgeDao.findTenantEdgeTypesAsync(tenantId.getId());
return Futures.transform(tenantEdgeTypes, return Futures.transform(tenantEdgeTypes,
edgeTypes -> { edgeTypes -> {
@ -400,7 +400,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<Edge> findEdgesByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, PageLink pageLink) { public PageData<Edge> findEdgesByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, PageLink pageLink) {
log.trace("Executing findEdgesByTenantIdAndEntityId, tenantId [{}], entityId [{}], pageLink [{}]", tenantId, entityId, pageLink); log.trace("Executing findEdgesByTenantIdAndEntityId, tenantId [{}], entityId [{}], pageLink [{}]", tenantId, entityId, pageLink);
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgesByTenantIdAndEntityId(tenantId.getId(), entityId.getId(), entityId.getEntityType(), pageLink); return edgeDao.findEdgesByTenantIdAndEntityId(tenantId.getId(), entityId.getId(), entityId.getEntityType(), pageLink);
} }
@ -408,7 +408,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
@Override @Override
public PageData<Edge> findEdgesByTenantProfileId(TenantProfileId tenantProfileId, PageLink pageLink) { public PageData<Edge> findEdgesByTenantProfileId(TenantProfileId tenantProfileId, PageLink pageLink) {
log.trace("Executing findEdgesByTenantProfileId, tenantProfileId [{}], pageLink [{}]", tenantProfileId, pageLink); log.trace("Executing findEdgesByTenantProfileId, tenantProfileId [{}], pageLink [{}]", tenantProfileId, pageLink);
Validator.validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId); Validator.validateId(tenantProfileId, id -> "Incorrect tenantProfileId " + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return edgeDao.findEdgesByTenantProfileId(tenantProfileId.getId(), pageLink); return edgeDao.findEdgesByTenantProfileId(tenantProfileId.getId(), pageLink);
} }

66
dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java

@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.HasEmail; import org.thingsboard.server.common.data.HasEmail;
import org.thingsboard.server.common.data.HasLabel; import org.thingsboard.server.common.data.HasLabel;
@ -34,13 +35,18 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityCountQuery;
import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityData;
import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery; import org.thingsboard.server.common.data.query.EntityDataQuery;
import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.EntityFilterType;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityListFilter;
import org.thingsboard.server.common.data.query.RelationsQueryFilter; import org.thingsboard.server.common.data.query.RelationsQueryFilter;
import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.exception.IncorrectParameterException;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.id.EntityId.NULL_UUID; import static org.thingsboard.server.common.data.id.EntityId.NULL_UUID;
import static org.thingsboard.server.dao.service.Validator.validateEntityDataPageLink; import static org.thingsboard.server.dao.service.Validator.validateEntityDataPageLink;
@ -67,8 +73,8 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
@Override @Override
public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query); log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateEntityCountQuery(query); validateEntityCountQuery(query);
return this.entityQueryDao.countEntitiesByQuery(tenantId, customerId, query); return this.entityQueryDao.countEntitiesByQuery(tenantId, customerId, query);
} }
@ -76,10 +82,56 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
@Override @Override
public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
log.trace("Executing findEntityDataByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query); log.trace("Executing findEntityDataByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validateEntityDataQuery(query); validateEntityDataQuery(query);
return this.entityQueryDao.findEntityDataByQuery(tenantId, customerId, query);
if (EntityFilterType.RELATIONS_QUERY.equals(query.getEntityFilter().getType())
|| EntityFilterType.SINGLE_ENTITY.equals(query.getEntityFilter().getType())
|| StringUtils.isNotEmpty(query.getPageLink().getTextSearch())) {
return this.entityQueryDao.findEntityDataByQuery(tenantId, customerId, query);
}
// 1 step - find entity data by filter and sort columns
PageData<EntityData> entityDataByQuery = findEntityIdsByFilterAndSorterColumns(tenantId, customerId, query);
if (entityDataByQuery == null || entityDataByQuery.getData().isEmpty()) {
return entityDataByQuery;
}
// 2 step - find entity data by entity ids from the 1st step
PageData<EntityData> result = findEntityDataByEntityIds(tenantId, customerId, query, entityDataByQuery.getData());
return new PageData<>(result.getData(), entityDataByQuery.getTotalPages(), entityDataByQuery.getTotalElements(), entityDataByQuery.hasNext());
}
private PageData<EntityData> findEntityIdsByFilterAndSorterColumns(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
List<EntityKey> entityFields = null;
List<EntityKey> latestValues = null;
if (query.getPageLink().getSortOrder() != null) {
if (query.getEntityFields() != null) {
entityFields = query.getEntityFields().stream()
.filter(entityKey -> entityKey.getKey().equals(query.getPageLink().getSortOrder().getKey().getKey()))
.collect(Collectors.toList());
}
if (query.getLatestValues() != null) {
latestValues = query.getLatestValues().stream()
.filter(entityKey -> entityKey.getKey().equals(query.getPageLink().getSortOrder().getKey().getKey()))
.collect(Collectors.toList());
}
}
EntityDataQuery entityQuery = new EntityDataQuery(query.getEntityFilter(), query.getPageLink(), entityFields, latestValues, query.getKeyFilters());
return this.entityQueryDao.findEntityDataByQuery(tenantId, customerId, entityQuery);
}
private PageData<EntityData> findEntityDataByEntityIds(TenantId tenantId, CustomerId customerId, EntityDataQuery query, List<EntityData> data) {
List<String> entityIds = data.stream().map(d -> d.getEntityId().getId().toString()).toList();
EntityType entityType = data.isEmpty() ? null : data.get(0).getEntityId().getEntityType();
EntityListFilter filter = new EntityListFilter();
filter.setEntityType(entityType);
filter.setEntityList(entityIds);
EntityDataPageLink pageLink = new EntityDataPageLink(query.getPageLink().getPageSize(), 0, null, query.getPageLink().getSortOrder());
EntityDataQuery entityQuery = new EntityDataQuery(filter, pageLink, query.getEntityFields(), query.getLatestValues(), null);
return this.entityQueryDao.findEntityDataByQuery(tenantId, customerId, entityQuery);
} }
@Override @Override
@ -133,8 +185,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
} }
private CustomerId getCustomerId(HasId<?> entity) { private CustomerId getCustomerId(HasId<?> entity) {
if (entity instanceof HasCustomerId) { if (entity instanceof HasCustomerId hasCustomerId) {
HasCustomerId hasCustomerId = (HasCustomerId) entity;
CustomerId customerId = hasCustomerId.getCustomerId(); CustomerId customerId = hasCustomerId.getCustomerId();
if (customerId == null) { if (customerId == null) {
customerId = NULL_CUSTOMER_ID; customerId = NULL_CUSTOMER_ID;
@ -176,4 +227,5 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
throw new IncorrectParameterException("Relation query filter root entity should not be blank"); throw new IncorrectParameterException("Relation query filter root entity should not be blank");
} }
} }
} }

68
dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java

@ -145,15 +145,15 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
customerEntityViewsUnAssigner.removeEntities(tenantId, customerId); customerEntityViewsUnAssigner.removeEntities(tenantId, customerId);
} }
@Override @Override
public EntityViewInfo findEntityViewInfoById(TenantId tenantId, EntityViewId entityViewId) { public EntityViewInfo findEntityViewInfoById(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing findEntityViewInfoById [{}]", entityViewId); log.trace("Executing findEntityViewInfoById [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id);
return entityViewDao.findEntityViewInfoById(tenantId, entityViewId.getId()); return entityViewDao.findEntityViewInfoById(tenantId, entityViewId.getId());
} }
@ -165,7 +165,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId, boolean putInCache) { public EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId, boolean putInCache) {
log.trace("Executing findEntityViewById [{}]", entityViewId); log.trace("Executing findEntityViewById [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id);
return cache.getOrFetchFromDB(EntityViewCacheKey.byId(entityViewId), return cache.getOrFetchFromDB(EntityViewCacheKey.byId(entityViewId),
() -> entityViewDao.findById(tenantId, entityViewId.getId()) () -> entityViewDao.findById(tenantId, entityViewId.getId())
, EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true, putInCache); , EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true, putInCache);
@ -174,7 +174,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name) { public EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name) {
log.trace("Executing findEntityViewByTenantIdAndName [{}][{}]", tenantId, name); log.trace("Executing findEntityViewByTenantIdAndName [{}][{}]", tenantId, name);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
return cache.getAndPutInTransaction(EntityViewCacheKey.byName(tenantId, name), return cache.getAndPutInTransaction(EntityViewCacheKey.byName(tenantId, name),
() -> entityViewDao.findEntityViewByTenantIdAndName(tenantId.getId(), name).orElse(null) () -> entityViewDao.findEntityViewByTenantIdAndName(tenantId.getId(), name).orElse(null)
, EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true); , EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true);
@ -184,7 +184,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public PageData<EntityView> findEntityViewByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<EntityView> findEntityViewByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findEntityViewsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findEntityViewsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return entityViewDao.findEntityViewsByTenantId(tenantId.getId(), pageLink); return entityViewDao.findEntityViewsByTenantId(tenantId.getId(), pageLink);
} }
@ -192,7 +192,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public PageData<EntityViewInfo> findEntityViewInfosByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<EntityViewInfo> findEntityViewInfosByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findEntityViewInfosByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); log.trace("Executing findEntityViewInfosByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return entityViewDao.findEntityViewInfosByTenantId(tenantId.getId(), pageLink); return entityViewDao.findEntityViewInfosByTenantId(tenantId.getId(), pageLink);
} }
@ -200,18 +200,18 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public PageData<EntityView> findEntityViewByTenantIdAndType(TenantId tenantId, PageLink pageLink, String type) { public PageData<EntityView> findEntityViewByTenantIdAndType(TenantId tenantId, PageLink pageLink, String type) {
log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], pageLink [{}], type [{}]", tenantId, pageLink, type); log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], pageLink [{}], type [{}]", tenantId, pageLink, type);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
return entityViewDao.findEntityViewsByTenantIdAndType(tenantId.getId(), type, pageLink); return entityViewDao.findEntityViewsByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@Override @Override
public PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { public PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findEntityViewInfosByTenantIdAndType, tenantId [{}], pageLink [{}], type [{}]", tenantId, pageLink, type); log.trace("Executing findEntityViewInfosByTenantIdAndType, tenantId [{}], pageLink [{}], type [{}]", tenantId, pageLink, type);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
return entityViewDao.findEntityViewInfosByTenantIdAndType(tenantId.getId(), type, pageLink); return entityViewDao.findEntityViewInfosByTenantIdAndType(tenantId.getId(), type, pageLink);
} }
@ -220,8 +220,8 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
PageLink pageLink) { PageLink pageLink) {
log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," +
" pageLink [{}]", tenantId, customerId, pageLink); " pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id ->INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), return entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(),
customerId.getId(), pageLink); customerId.getId(), pageLink);
@ -231,8 +231,8 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
public PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { public PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findEntityViewInfosByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + log.trace("Executing findEntityViewInfosByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," +
" pageLink [{}]", tenantId, customerId, pageLink); " pageLink [{}]", tenantId, customerId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return entityViewDao.findEntityViewInfosByTenantIdAndCustomerId(tenantId.getId(), return entityViewDao.findEntityViewInfosByTenantIdAndCustomerId(tenantId.getId(),
customerId.getId(), pageLink); customerId.getId(), pageLink);
@ -242,10 +242,10 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
public PageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, PageLink pageLink, String type) { public PageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, PageLink pageLink, String type) {
log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," + log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," +
" pageLink [{}], type [{}]", tenantId, customerId, pageLink, type); " pageLink [{}], type [{}]", tenantId, customerId, pageLink, type);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
return entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId.getId(), return entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId.getId(),
customerId.getId(), type, pageLink); customerId.getId(), type, pageLink);
} }
@ -254,10 +254,10 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
public PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) { public PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink) {
log.trace("Executing findEntityViewInfosByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," + log.trace("Executing findEntityViewInfosByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," +
" pageLink [{}], type [{}]", tenantId, customerId, pageLink, type); " pageLink [{}], type [{}]", tenantId, customerId, pageLink, type);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validateId(customerId, id -> INCORRECT_CUSTOMER_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
return entityViewDao.findEntityViewInfosByTenantIdAndCustomerIdAndType(tenantId.getId(), return entityViewDao.findEntityViewInfosByTenantIdAndCustomerIdAndType(tenantId.getId(),
customerId.getId(), type, pageLink); customerId.getId(), type, pageLink);
} }
@ -291,15 +291,15 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public ListenableFuture<EntityView> findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId) { public ListenableFuture<EntityView> findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing findEntityViewById [{}]", entityViewId); log.trace("Executing findEntityViewById [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id);
return entityViewDao.findByIdAsync(tenantId, entityViewId.getId()); return entityViewDao.findByIdAsync(tenantId, entityViewId.getId());
} }
@Override @Override
public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) {
log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(entityId.getId(), "Incorrect entityId" + entityId); validateId(entityId.getId(), id -> "Incorrect entityId" + id);
return service.submit(() -> cache.getAndPutInTransaction(EntityViewCacheKey.byEntityId(tenantId, entityId), return service.submit(() -> cache.getAndPutInTransaction(EntityViewCacheKey.byEntityId(tenantId, entityId),
() -> entityViewDao.findEntityViewsByTenantIdAndEntityId(tenantId.getId(), entityId.getId()), () -> entityViewDao.findEntityViewsByTenantIdAndEntityId(tenantId.getId(), entityId.getId()),
@ -309,8 +309,8 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public List<EntityView> findEntityViewsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId) { public List<EntityView> findEntityViewsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId) {
log.trace("Executing findEntityViewsByTenantIdAndEntityId, tenantId [{}], entityId [{}]", tenantId, entityId); log.trace("Executing findEntityViewsByTenantIdAndEntityId, tenantId [{}], entityId [{}]", tenantId, entityId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(entityId.getId(), "Incorrect entityId" + entityId); validateId(entityId.getId(), id -> "Incorrect entityId" + id);
return cache.getAndPutInTransaction(EntityViewCacheKey.byEntityId(tenantId, entityId), return cache.getAndPutInTransaction(EntityViewCacheKey.byEntityId(tenantId, entityId),
() -> entityViewDao.findEntityViewsByTenantIdAndEntityId(tenantId.getId(), entityId.getId()), () -> entityViewDao.findEntityViewsByTenantIdAndEntityId(tenantId.getId(), entityId.getId()),
@ -326,7 +326,7 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Transactional @Transactional
public void deleteEntityView(TenantId tenantId, EntityViewId entityViewId) { public void deleteEntityView(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing deleteEntityView [{}]", entityViewId); log.trace("Executing deleteEntityView [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id);
deleteEntityRelations(tenantId, entityViewId); deleteEntityRelations(tenantId, entityViewId);
EntityView entityView = entityViewDao.findById(tenantId, entityViewId.getId()); EntityView entityView = entityViewDao.findById(tenantId, entityViewId.getId());
entityViewDao.removeById(tenantId, entityViewId.getId()); entityViewDao.removeById(tenantId, entityViewId.getId());
@ -337,14 +337,14 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public void deleteEntityViewsByTenantId(TenantId tenantId) { public void deleteEntityViewsByTenantId(TenantId tenantId) {
log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
tenantEntityViewRemover.removeEntities(tenantId, tenantId); tenantEntityViewRemover.removeEntities(tenantId, tenantId);
} }
@Override @Override
public ListenableFuture<List<EntitySubtype>> findEntityViewTypesByTenantId(TenantId tenantId) { public ListenableFuture<List<EntitySubtype>> findEntityViewTypesByTenantId(TenantId tenantId) {
log.trace("Executing findEntityViewTypesByTenantId, tenantId [{}]", tenantId); log.trace("Executing findEntityViewTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
ListenableFuture<List<EntitySubtype>> tenantEntityViewTypes = entityViewDao.findTenantEntityViewTypesAsync(tenantId.getId()); ListenableFuture<List<EntitySubtype>> tenantEntityViewTypes = entityViewDao.findTenantEntityViewTypesAsync(tenantId.getId());
return Futures.transform(tenantEntityViewTypes, return Futures.transform(tenantEntityViewTypes,
entityViewTypes -> { entityViewTypes -> {
@ -402,8 +402,8 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public PageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) { public PageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink) {
log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
validatePageLink(pageLink); validatePageLink(pageLink);
return entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); return entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink);
} }
@ -411,9 +411,9 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
@Override @Override
public PageData<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink) { public PageData<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink) {
log.trace("Executing findEntityViewsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink); log.trace("Executing findEntityViewsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(edgeId, INCORRECT_EDGE_ID + edgeId); validateId(edgeId, id -> INCORRECT_EDGE_ID + id);
validateString(type, "Incorrect type " + type); validateString(type, t -> "Incorrect type " + t);
validatePageLink(pageLink); validatePageLink(pageLink);
return entityViewDao.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); return entityViewDao.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink);
} }

9
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -427,6 +427,7 @@ public class ModelConstants {
*/ */
public static final String OAUTH2_PARAMS_TABLE_NAME = "oauth2_params"; public static final String OAUTH2_PARAMS_TABLE_NAME = "oauth2_params";
public static final String OAUTH2_PARAMS_ENABLED_PROPERTY = "enabled"; public static final String OAUTH2_PARAMS_ENABLED_PROPERTY = "enabled";
public static final String OAUTH2_PARAMS_EDGE_ENABLED_PROPERTY = "edge_enabled";
public static final String OAUTH2_PARAMS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String OAUTH2_PARAMS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String OAUTH2_REGISTRATION_TABLE_NAME = "oauth2_registration"; public static final String OAUTH2_REGISTRATION_TABLE_NAME = "oauth2_registration";
@ -610,6 +611,14 @@ public class ModelConstants {
public static final String QUEUE_TABLE_NAME = "queue"; public static final String QUEUE_TABLE_NAME = "queue";
public static final String QUEUE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; public static final String QUEUE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
/**
* Tenant queue stats constants.
*/
public static final String QUEUE_STATS_TABLE_NAME = "queue_stats";
public static final String QUEUE_STATS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String QUEUE_STATS_QUEUE_NAME_PROPERTY = "queue_name";
public static final String QUEUE_STATS_SERVICE_ID_PROPERTY = "service_id";
/** /**
* Notification constants * Notification constants
*/ */

5
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java

@ -39,6 +39,9 @@ public class OAuth2ParamsEntity extends BaseSqlEntity<OAuth2Params> {
@Column(name = ModelConstants.OAUTH2_PARAMS_ENABLED_PROPERTY) @Column(name = ModelConstants.OAUTH2_PARAMS_ENABLED_PROPERTY)
private Boolean enabled; private Boolean enabled;
@Column(name = ModelConstants.OAUTH2_PARAMS_EDGE_ENABLED_PROPERTY)
private Boolean edgeEnabled;
@Column(name = ModelConstants.OAUTH2_PARAMS_TENANT_ID_PROPERTY) @Column(name = ModelConstants.OAUTH2_PARAMS_TENANT_ID_PROPERTY)
private UUID tenantId; private UUID tenantId;
@ -48,6 +51,7 @@ public class OAuth2ParamsEntity extends BaseSqlEntity<OAuth2Params> {
} }
this.setCreatedTime(oauth2Params.getCreatedTime()); this.setCreatedTime(oauth2Params.getCreatedTime());
this.enabled = oauth2Params.isEnabled(); this.enabled = oauth2Params.isEnabled();
this.edgeEnabled = oauth2Params.isEdgeEnabled();
if (oauth2Params.getTenantId() != null) { if (oauth2Params.getTenantId() != null) {
this.tenantId = oauth2Params.getTenantId().getId(); this.tenantId = oauth2Params.getTenantId().getId();
} }
@ -60,6 +64,7 @@ public class OAuth2ParamsEntity extends BaseSqlEntity<OAuth2Params> {
oauth2Params.setCreatedTime(createdTime); oauth2Params.setCreatedTime(createdTime);
oauth2Params.setTenantId(TenantId.fromUUID(tenantId)); oauth2Params.setTenantId(TenantId.fromUUID(tenantId));
oauth2Params.setEnabled(enabled); oauth2Params.setEnabled(enabled);
oauth2Params.setEdgeEnabled(edgeEnabled);
return oauth2Params; return oauth2Params;
} }
} }

69
dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueStatsEntity.java

@ -0,0 +1,69 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.QueueStatsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.QueueStats;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import java.util.UUID;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = ModelConstants.QUEUE_STATS_TABLE_NAME)
public class QueueStatsEntity extends BaseSqlEntity<QueueStats> {
@Column(name = ModelConstants.QUEUE_STATS_TENANT_ID_PROPERTY)
private UUID tenantId;
@Column(name = ModelConstants.QUEUE_STATS_QUEUE_NAME_PROPERTY)
private String queueName;
@Column(name = ModelConstants.QUEUE_STATS_SERVICE_ID_PROPERTY)
private String serviceId;
public QueueStatsEntity() {
}
public QueueStatsEntity(QueueStats queueStats) {
if (queueStats.getId() != null) {
this.setId(queueStats.getId().getId());
}
this.setCreatedTime(queueStats.getCreatedTime());
this.tenantId = DaoUtil.getId(queueStats.getTenantId());
this.queueName = queueStats.getQueueName();
this.serviceId = queueStats.getServiceId();
}
@Override
public QueueStats toData() {
QueueStats queueStats = new QueueStats(new QueueStatsId(getUuid()));
queueStats.setCreatedTime(createdTime);
queueStats.setTenantId(new TenantId(tenantId));
queueStats.setQueueName(queueName);
queueStats.setServiceId(serviceId);
return queueStats;
}
}

6
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ConfigTemplateServiceImpl.java

@ -64,14 +64,14 @@ public class OAuth2ConfigTemplateServiceImpl extends AbstractEntityService imple
@Override @Override
public Optional<OAuth2ClientRegistrationTemplate> findClientRegistrationTemplateByProviderId(String providerId) { public Optional<OAuth2ClientRegistrationTemplate> findClientRegistrationTemplateByProviderId(String providerId) {
log.trace("Executing findClientRegistrationTemplateByProviderId [{}]", providerId); log.trace("Executing findClientRegistrationTemplateByProviderId [{}]", providerId);
validateString(providerId, INCORRECT_CLIENT_REGISTRATION_PROVIDER_ID + providerId); validateString(providerId, id -> INCORRECT_CLIENT_REGISTRATION_PROVIDER_ID + id);
return clientRegistrationTemplateDao.findByProviderId(providerId); return clientRegistrationTemplateDao.findByProviderId(providerId);
} }
@Override @Override
public OAuth2ClientRegistrationTemplate findClientRegistrationTemplateById(OAuth2ClientRegistrationTemplateId templateId) { public OAuth2ClientRegistrationTemplate findClientRegistrationTemplateById(OAuth2ClientRegistrationTemplateId templateId) {
log.trace("Executing findClientRegistrationTemplateById [{}]", templateId); log.trace("Executing findClientRegistrationTemplateById [{}]", templateId);
validateId(templateId, INCORRECT_CLIENT_REGISTRATION_TEMPLATE_ID + templateId); validateId(templateId, id -> INCORRECT_CLIENT_REGISTRATION_TEMPLATE_ID + id);
return clientRegistrationTemplateDao.findById(TenantId.SYS_TENANT_ID, templateId.getId()); return clientRegistrationTemplateDao.findById(TenantId.SYS_TENANT_ID, templateId.getId());
} }
@ -84,7 +84,7 @@ public class OAuth2ConfigTemplateServiceImpl extends AbstractEntityService imple
@Override @Override
public void deleteClientRegistrationTemplateById(OAuth2ClientRegistrationTemplateId templateId) { public void deleteClientRegistrationTemplateById(OAuth2ClientRegistrationTemplateId templateId) {
log.trace("Executing deleteClientRegistrationTemplateById [{}]", templateId); log.trace("Executing deleteClientRegistrationTemplateById [{}]", templateId);
validateId(templateId, INCORRECT_CLIENT_REGISTRATION_TEMPLATE_ID + templateId); validateId(templateId, id -> INCORRECT_CLIENT_REGISTRATION_TEMPLATE_ID + id);
clientRegistrationTemplateDao.removeById(TenantId.SYS_TENANT_ID, templateId.getId()); clientRegistrationTemplateDao.removeById(TenantId.SYS_TENANT_ID, templateId.getId());
} }
} }

12
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java

@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.SchemeType; import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.common.data.oauth2.TenantNameStrategyType; import org.thingsboard.server.common.data.oauth2.TenantNameStrategyType;
import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.exception.IncorrectParameterException;
@ -58,6 +59,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
@Slf4j @Slf4j
@Service @Service
public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Service { public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Service {
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
public static final String INCORRECT_CLIENT_REGISTRATION_ID = "Incorrect clientRegistrationId "; public static final String INCORRECT_CLIENT_REGISTRATION_ID = "Incorrect clientRegistrationId ";
public static final String INCORRECT_DOMAIN_NAME = "Incorrect domainName "; public static final String INCORRECT_DOMAIN_NAME = "Incorrect domainName ";
@ -84,7 +86,7 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
} catch (IllegalArgumentException e){ } catch (IllegalArgumentException e){
throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME); throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME);
} }
validateString(domainName, INCORRECT_DOMAIN_NAME + domainName); validateString(domainName, dn -> INCORRECT_DOMAIN_NAME + dn);
return oauth2RegistrationDao.findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType( return oauth2RegistrationDao.findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(
Arrays.asList(domainScheme, SchemeType.MIXED), domainName, pkgName, platformType) Arrays.asList(domainScheme, SchemeType.MIXED), domainName, pkgName, platformType)
.stream() .stream()
@ -116,6 +118,7 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
}); });
} }
}); });
eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(TenantId.SYS_TENANT_ID).entity(oauth2Info).build());
} }
@Override @Override
@ -123,7 +126,8 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
log.trace("Executing findOAuth2Info"); log.trace("Executing findOAuth2Info");
OAuth2Info oauth2Info = new OAuth2Info(); OAuth2Info oauth2Info = new OAuth2Info();
List<OAuth2Params> oauth2ParamsList = oauth2ParamsDao.find(TenantId.SYS_TENANT_ID); List<OAuth2Params> oauth2ParamsList = oauth2ParamsDao.find(TenantId.SYS_TENANT_ID);
oauth2Info.setEnabled(oauth2ParamsList.stream().anyMatch(param -> param.isEnabled())); oauth2Info.setEnabled(oauth2ParamsList.stream().anyMatch(OAuth2Params::isEnabled));
oauth2Info.setEdgeEnabled(oauth2ParamsList.stream().anyMatch(OAuth2Params::isEdgeEnabled));
List<OAuth2ParamsInfo> oauth2ParamsInfos = new ArrayList<>(); List<OAuth2ParamsInfo> oauth2ParamsInfos = new ArrayList<>();
oauth2Info.setOauth2ParamsInfos(oauth2ParamsInfos); oauth2Info.setOauth2ParamsInfos(oauth2ParamsInfos);
oauth2ParamsList.stream().sorted(Comparator.comparing(BaseData::getUuidId)).forEach(oauth2Params -> { oauth2ParamsList.stream().sorted(Comparator.comparing(BaseData::getUuidId)).forEach(oauth2Params -> {
@ -138,14 +142,14 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
@Override @Override
public OAuth2Registration findRegistration(UUID id) { public OAuth2Registration findRegistration(UUID id) {
log.trace("Executing findRegistration [{}]", id); log.trace("Executing findRegistration [{}]", id);
validateId(id, INCORRECT_CLIENT_REGISTRATION_ID + id); validateId(id, uuid -> INCORRECT_CLIENT_REGISTRATION_ID + uuid);
return oauth2RegistrationDao.findById(null, id); return oauth2RegistrationDao.findById(null, id);
} }
@Override @Override
public String findAppSecret(UUID id, String pkgName) { public String findAppSecret(UUID id, String pkgName) {
log.trace("Executing findAppSecret [{}][{}]", id, pkgName); log.trace("Executing findAppSecret [{}][{}]", id, pkgName);
validateId(id, INCORRECT_CLIENT_REGISTRATION_ID + id); validateId(id, uuid -> INCORRECT_CLIENT_REGISTRATION_ID + uuid);
validateString(pkgName, "Incorrect package name"); validateString(pkgName, "Incorrect package name");
return oauth2RegistrationDao.findAppSecret(id, pkgName); return oauth2RegistrationDao.findAppSecret(id, pkgName);
} }

1
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java

@ -88,6 +88,7 @@ public class OAuth2Utils {
public static OAuth2Params infoToOAuth2Params(OAuth2Info oauth2Info) { public static OAuth2Params infoToOAuth2Params(OAuth2Info oauth2Info) {
OAuth2Params oauth2Params = new OAuth2Params(); OAuth2Params oauth2Params = new OAuth2Params();
oauth2Params.setEnabled(oauth2Info.isEnabled()); oauth2Params.setEnabled(oauth2Info.isEnabled());
oauth2Params.setEdgeEnabled(oauth2Info.isEdgeEnabled());
oauth2Params.setTenantId(TenantId.SYS_TENANT_ID); oauth2Params.setTenantId(TenantId.SYS_TENANT_ID);
return oauth2Params; return oauth2Params;
} }

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

Loading…
Cancel
Save