Browse Source

Merge remote-tracking branch 'origin/develop/3.4' into feature/work-1581-replace-deprecated-stringutils

pull/6923/head
thingsboard 4 years ago
parent
commit
87325bcd10
  1. 3
      application/src/main/data/upgrade/3.3.4/schema_update.sql
  2. 49
      application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql
  3. 7
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  4. 56
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  5. 2
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  6. 8
      application/src/main/java/org/thingsboard/server/controller/QueueController.java
  7. 1
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  8. 5
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java
  9. 7
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
  10. 30
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
  11. 9
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java
  12. 6
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java
  13. 50
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV333.java
  14. 5
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java
  15. 28
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java
  16. 53
      application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
  17. 31
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  18. 4
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  19. 44
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
  20. 10
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  21. 10
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
  22. 2
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
  23. 6
      application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java
  24. 6
      application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java
  25. 1
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
  26. 2
      application/src/main/resources/thingsboard.yml
  27. 7
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  28. 57
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
  29. 18
      application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java
  30. 7
      application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java
  31. 22
      application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java
  32. 95
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/AbstractCoapAttributesIntegrationTest.java
  33. 62
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java
  34. 1
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcJsonIntegrationTest.java
  35. 6
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java
  36. 1
      common/cluster-api/src/main/proto/queue.proto
  37. 16
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java
  38. 8
      common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java
  39. 2
      common/edge-api/src/main/proto/edge.proto
  40. 48
      common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
  41. 38
      common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java
  42. 5
      common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java
  43. 1
      common/queue/src/main/java/org/thingsboard/server/queue/discovery/TenantRoutingInfo.java
  44. 10
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  45. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportTenantRoutingInfoService.java
  46. 3
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java
  47. 6
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  48. 1
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  49. 13
      dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java
  50. 5
      dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java
  51. 15
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  52. 9
      dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java
  53. 2
      dao/src/main/java/org/thingsboard/server/dao/service/validator/TenantProfileDataValidator.java
  54. 1
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java
  55. 1
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  56. 2
      dao/src/main/resources/sql/schema-entities-idx.sql
  57. 3
      dao/src/main/resources/sql/schema-entities.sql
  58. 1
      dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java
  59. 10
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java
  60. 1
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java
  61. 2
      msa/vc-executor/src/main/java/org/thingsboard/server/vc/service/VersionControlTenantRoutingInfoService.java
  62. 13
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
  63. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java
  64. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java
  65. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java
  66. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java
  67. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java
  68. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java
  69. 2
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  70. 2
      transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java
  71. 4
      ui-ngx/src/app/core/http/queue.service.ts
  72. 5
      ui-ngx/src/app/core/services/dashboard-utils.service.ts
  73. 34
      ui-ngx/src/app/core/services/item-buffer.service.ts
  74. 1
      ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts
  75. 2
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html
  76. 7
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
  77. 2
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.html
  78. 8
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts
  79. 4
      ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html
  80. 3
      ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts
  81. 3
      ui-ngx/src/app/modules/home/components/widget/widget-container.component.html
  82. 4
      ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss
  83. 2
      ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html
  84. 11
      ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts
  85. 2
      ui-ngx/src/app/modules/home/models/dashboard-component.models.ts
  86. 5
      ui-ngx/src/app/shared/components/markdown.component.ts
  87. 6
      ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html
  88. 33
      ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts
  89. 3
      ui-ngx/src/app/shared/models/device.models.ts
  90. 1
      ui-ngx/src/app/shared/models/tenant.model.ts
  91. 2
      ui-ngx/src/assets/locale/locale.constant-cs_CZ.json
  92. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  93. 2
      ui-ngx/src/assets/locale/locale.constant-es_ES.json
  94. 2
      ui-ngx/src/assets/locale/locale.constant-ko_KR.json
  95. 2
      ui-ngx/src/assets/locale/locale.constant-pt_BR.json
  96. 2
      ui-ngx/src/assets/locale/locale.constant-sl_SI.json
  97. 2
      ui-ngx/src/assets/locale/locale.constant-tr_TR.json
  98. 2
      ui-ngx/src/assets/locale/locale.constant-zh_CN.json

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

@ -70,3 +70,6 @@ CREATE TABLE IF NOT EXISTS user_auth_settings (
two_fa_settings varchar two_fa_settings varchar
); );
CREATE INDEX IF NOT EXISTS idx_api_usage_state_entity_id ON api_usage_state(entity_id);
ALTER TABLE tenant_profile DROP COLUMN IF EXISTS isolated_tb_core;

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

@ -1,49 +0,0 @@
--
-- Copyright © 2016-2022 The Thingsboard Authors
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
ALTER TABLE device_profile
ADD COLUMN IF NOT EXISTS default_queue_id uuid;
DO
$$
BEGIN
IF EXISTS
(SELECT column_name
FROM information_schema.columns
WHERE table_name = 'device_profile'
AND column_name = 'default_queue_name'
)
THEN
UPDATE device_profile
SET default_queue_id = q.id
FROM queue as q
WHERE default_queue_name = q.name;
END IF;
END
$$;
DO
$$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_queue_device_profile') THEN
ALTER TABLE device_profile
ADD CONSTRAINT fk_default_queue_device_profile FOREIGN KEY (default_queue_id) REFERENCES queue (id);
END IF;
END;
$$;
ALTER TABLE device_profile
DROP COLUMN IF EXISTS default_queue_name;

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

@ -508,13 +508,8 @@ public class ActorSystemContext {
return partitionService.resolve(serviceType, tenantId, entityId); return partitionService.resolve(serviceType, tenantId, entityId);
} }
public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) {
return partitionService.resolve(serviceType, queueId, tenantId, entityId);
}
@Deprecated
public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) { public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) {
return partitionService.resolve(serviceType, tenantId, entityId, queueName); return partitionService.resolve(serviceType, queueName, tenantId, entityId);
} }
public String getServiceId() { public String getServiceId() {

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

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

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

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

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

@ -75,6 +75,14 @@ public class QueueController extends BaseController {
return checkNotNull(queueService.findQueueById(getTenantId(), queueId)); return checkNotNull(queueService.findQueueById(getTenantId(), queueId));
} }
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/name/{queueName}", method = RequestMethod.GET)
@ResponseBody
public Queue getQueueByName(@PathVariable("queueName") String queueName) throws ThingsboardException {
checkParameter("queueName", queueName);
return checkNotNull(queueService.findQueueByTenantIdAndName(getTenantId(), queueName));
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST) @RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST)
@ResponseBody @ResponseBody

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

@ -128,7 +128,6 @@ public class TenantProfileController extends BaseController {
"{\n" + "{\n" +
" \"name\": \"Default\",\n" + " \"name\": \"Default\",\n" +
" \"description\": \"Default tenant profile\",\n" + " \"description\": \"Default tenant profile\",\n" +
" \"isolatedTbCore\": false,\n" +
" \"isolatedTbRuleEngine\": false,\n" + " \"isolatedTbRuleEngine\": false,\n" +
" \"profileData\": {\n" + " \"profileData\": {\n" +
" \"configuration\": {\n" + " \"configuration\": {\n" +

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

@ -48,9 +48,8 @@ public class DeviceProfileMsgConstructor {
// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits()) // builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits()); // .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());
// } // }
if (deviceProfile.getDefaultQueueId() != null) { if (deviceProfile.getDefaultQueueName() != null) {
builder.setDefaultQueueIdMSB(deviceProfile.getDefaultQueueId().getId().getMostSignificantBits()) builder.setDefaultQueueName(deviceProfile.getDefaultQueueName());
.setDefaultQueueIdLSB(deviceProfile.getDefaultQueueId().getId().getLeastSignificantBits());
} }
if (deviceProfile.getDescription() != null) { if (deviceProfile.getDescription() != null) {
builder.setDescription(deviceProfile.getDescription()); builder.setDescription(deviceProfile.getDescription());

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

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
@ -23,7 +22,6 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
@ -35,11 +33,8 @@ import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadat
@Component @Component
@Slf4j @Slf4j
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor
public class RuleChainMsgConstructor { public class RuleChainMsgConstructor {
private final QueueService queueService;
public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) { public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder() RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
@ -61,7 +56,7 @@ public class RuleChainMsgConstructor {
RuleChainMetaData ruleChainMetaData, RuleChainMetaData ruleChainMetaData,
EdgeVersion edgeVersion) { EdgeVersion edgeVersion) {
RuleChainMetadataConstructor ruleChainMetadataConstructor RuleChainMetadataConstructor ruleChainMetadataConstructor
= RuleChainMetadataConstructorFactory.getByEdgeVersion(edgeVersion, queueService); = RuleChainMetadataConstructorFactory.getByEdgeVersion(edgeVersion);
return ruleChainMetadataConstructor.constructRuleChainMetadataUpdatedMsg(tenantId, msgType, ruleChainMetaData); return ruleChainMetadataConstructor.constructRuleChainMetadataUpdatedMsg(tenantId, msgType, ruleChainMetaData);
} }

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

@ -16,20 +16,15 @@
package org.thingsboard.server.service.edge.rpc.constructor.rule; package org.thingsboard.server.service.edge.rpc.constructor.rule;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbCheckpointNode;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto; import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto; import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
@ -39,16 +34,11 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.NavigableSet; import java.util.NavigableSet;
import java.util.UUID;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
public abstract class AbstractRuleChainMetadataConstructor implements RuleChainMetadataConstructor { public abstract class AbstractRuleChainMetadataConstructor implements RuleChainMetadataConstructor {
public static final List<String> nodeTypes = List.of(TbCheckpointNode.class.getName());
private final QueueService queueService;
@Override @Override
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId, public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
UpdateMsgType msgType, UpdateMsgType msgType,
@ -144,24 +134,4 @@ public abstract class AbstractRuleChainMetadataConstructor implements RuleChainM
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo())) .setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo()))
.build(); .build();
} }
protected List<RuleNode> updateQueueIdToQueueNameNodeConfiguration(TenantId tenantId, List<RuleNode> nodes) {
List<RuleNode> result = new ArrayList<>();
for (RuleNode node : nodes) {
if (nodeTypes.contains(node.getType())) {
ObjectNode configuration = (ObjectNode) node.getConfiguration();
JsonNode queueIdNode = configuration.remove("queueId");
if (queueIdNode != null) {
String queueId = queueIdNode.asText();
Queue queueById = queueService.findQueueById(tenantId, new QueueId(UUID.fromString(queueId)));
if (queueById != null) {
configuration.put("queueName", queueById.getName());
node.setConfiguration(configuration);
}
}
}
result.add(node);
}
return result;
}
} }

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

@ -15,21 +15,18 @@
*/ */
package org.thingsboard.server.service.edge.rpc.constructor.rule; package org.thingsboard.server.service.edge.rpc.constructor.rule;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.EdgeVersion;
public final class RuleChainMetadataConstructorFactory { public final class RuleChainMetadataConstructorFactory {
public static RuleChainMetadataConstructor getByEdgeVersion(EdgeVersion edgeVersion, public static RuleChainMetadataConstructor getByEdgeVersion(EdgeVersion edgeVersion) {
QueueService queueService) {
switch (edgeVersion) { switch (edgeVersion) {
case V_3_3_0: case V_3_3_0:
return new RuleChainMetadataConstructorV330(queueService); return new RuleChainMetadataConstructorV330();
case V_3_3_3: case V_3_3_3:
return new RuleChainMetadataConstructorV333(queueService);
case V_3_4_0: case V_3_4_0:
default: default:
return new RuleChainMetadataConstructorV340(queueService); return new RuleChainMetadataConstructorV340();
} }
} }
} }

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

@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.ArrayList; import java.util.ArrayList;
@ -43,16 +42,11 @@ public class RuleChainMetadataConstructorV330 extends AbstractRuleChainMetadataC
private static final String RULE_CHAIN_INPUT_NODE = TbRuleChainInputNode.class.getName(); private static final String RULE_CHAIN_INPUT_NODE = TbRuleChainInputNode.class.getName();
private static final String TB_RULE_CHAIN_OUTPUT_NODE = TbRuleChainOutputNode.class.getName(); private static final String TB_RULE_CHAIN_OUTPUT_NODE = TbRuleChainOutputNode.class.getName();
public RuleChainMetadataConstructorV330(QueueService queueService) {
super(queueService);
}
@Override @Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId, protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder, RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException { RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
List<RuleNode> supportedNodes = filterNodes(ruleChainMetaData.getNodes()); List<RuleNode> supportedNodes = filterNodes(ruleChainMetaData.getNodes());
supportedNodes = updateQueueIdToQueueNameNodeConfiguration(tenantId, supportedNodes);
NavigableSet<Integer> removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections()); NavigableSet<Integer> removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections());
List<NodeConnectionInfo> connections = filterConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes); List<NodeConnectionInfo> connections = filterConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes);

50
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV333.java

@ -1,50 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor.rule;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.List;
import java.util.TreeSet;
@Slf4j
public class RuleChainMetadataConstructorV333 extends AbstractRuleChainMetadataConstructor {
public RuleChainMetadataConstructorV333(QueueService queueService) {
super(queueService);
}
@Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
List<RuleNode> nodes = updateQueueIdToQueueNameNodeConfiguration(tenantId, ruleChainMetaData.getNodes());
builder.addAllNodes(constructNodes(nodes))
.addAllConnections(constructConnections(ruleChainMetaData.getConnections()))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections(), new TreeSet<>()));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
} else {
builder.setFirstNodeIndex(-1);
}
}
}

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

@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.TreeSet; import java.util.TreeSet;
@ -27,10 +26,6 @@ import java.util.TreeSet;
@Slf4j @Slf4j
public class RuleChainMetadataConstructorV340 extends AbstractRuleChainMetadataConstructor { public class RuleChainMetadataConstructorV340 extends AbstractRuleChainMetadataConstructor {
public RuleChainMetadataConstructorV340(QueueService queueService) {
super(queueService);
}
@Override @Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId, protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder, RuleChainMetadataUpdateMsg.Builder builder,

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

@ -158,21 +158,21 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
return metaData; return metaData;
} }
private Pair<QueueId, RuleChainId> getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) { private Pair<String, RuleChainId> getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) {
if (EntityType.DEVICE.equals(entityId.getEntityType())) { if (EntityType.DEVICE.equals(entityId.getEntityType())) {
DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())); DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
RuleChainId ruleChainId; RuleChainId ruleChainId;
QueueId queueId; String queueName;
if (deviceProfile == null) { if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", entityId); log.warn("[{}] Device profile is null!", entityId);
ruleChainId = null; ruleChainId = null;
queueId = null; queueName = null;
} else { } else {
ruleChainId = deviceProfile.getDefaultRuleChainId(); ruleChainId = deviceProfile.getDefaultRuleChainId();
queueId = deviceProfile.getDefaultQueueId(); queueName = deviceProfile.getDefaultQueueName();
} }
return new ImmutablePair<>(queueId, ruleChainId); return new ImmutablePair<>(queueName, ruleChainId);
} else { } else {
return new ImmutablePair<>(null, null); return new ImmutablePair<>(null, null);
} }
@ -183,10 +183,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + ""); metaData.putValue("ts", tsKv.getTs() + "");
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey(); TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { public void onSuccess(TbQueueMsgMetadata metadata) {
@ -206,10 +204,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
private ListenableFuture<Void> processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { private ListenableFuture<Void> processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
SettableFuture<Void> futureToSet = SettableFuture.create(); SettableFuture<Void> futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey(); TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { public void onSuccess(TbQueueMsgMetadata metadata) {
@ -233,10 +229,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
Futures.addCallback(future, new FutureCallback<>() { Futures.addCallback(future, new FutureCallback<>() {
@Override @Override
public void onSuccess(@Nullable List<String> keys) { public void onSuccess(@Nullable List<String> keys) {
Pair<QueueId, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
QueueId queueId = defaultQueueAndRuleChain.getKey(); TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
TbMsg tbMsg = TbMsg.newMsg(queueId, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { public void onSuccess(TbQueueMsgMetadata metadata) {

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

@ -48,13 +48,11 @@ import java.util.stream.Collectors;
@TbCoreComponent @TbCoreComponent
@AllArgsConstructor @AllArgsConstructor
public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService { public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService {
private static final String MAIN = "Main";
private static final long DELETE_DELAY = 30; private static final long DELETE_DELAY = 30;
private final QueueService queueService; private final QueueService queueService;
private final TbClusterService tbClusterService; private final TbClusterService tbClusterService;
private final TbQueueAdmin tbQueueAdmin; private final TbQueueAdmin tbQueueAdmin;
private final DeviceProfileService deviceProfileService;
private final SchedulerComponent scheduler; private final SchedulerComponent scheduler;
@Override @Override
@ -205,35 +203,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
} }
tenantIds.forEach(tenantId -> { tenantIds.forEach(tenantId -> {
Map<QueueId, List<DeviceProfile>> deviceProfileQueues; toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key))));
if (oldTenantProfile != null && !newTenantProfile.getId().equals(oldTenantProfile.getId()) || !toRemove.isEmpty()) {
List<DeviceProfile> deviceProfiles = deviceProfileService.findDeviceProfiles(tenantId, new PageLink(Integer.MAX_VALUE)).getData();
deviceProfileQueues = deviceProfiles.stream()
.filter(dp -> dp.getDefaultQueueId() != null)
.collect(Collectors.groupingBy(DeviceProfile::getDefaultQueueId));
} else {
deviceProfileQueues = Collections.emptyMap();
}
Map<String, QueueId> createdQueues = toCreate.stream()
.map(key -> saveQueue(new Queue(tenantId, newQueues.get(key))))
.collect(Collectors.toMap(Queue::getName, Queue::getId));
// assigning created queues to device profiles instead of system queues
if (oldTenantProfile != null && !oldTenantProfile.isIsolatedTbRuleEngine()) {
deviceProfileQueues.forEach((queueId, list) -> {
Queue queue = queueService.findQueueById(TenantId.SYS_TENANT_ID, queueId);
QueueId queueIdToAssign = createdQueues.get(queue.getName());
if (queueIdToAssign == null) {
queueIdToAssign = createdQueues.get(MAIN);
}
for (DeviceProfile deviceProfile : list) {
deviceProfile.setDefaultQueueId(queueIdToAssign);
saveDeviceProfile(deviceProfile);
}
});
}
toUpdate.forEach(key -> { toUpdate.forEach(key -> {
Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); Queue queueToUpdate = new Queue(tenantId, newQueues.get(key));
@ -241,9 +211,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
queueToUpdate.setId(foundQueue.getId()); queueToUpdate.setId(foundQueue.getId());
queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); queueToUpdate.setCreatedTime(foundQueue.getCreatedTime());
if (queueToUpdate.equals(foundQueue)) { if (!queueToUpdate.equals(foundQueue)) {
//Queue not changed
} else {
saveQueue(queueToUpdate); saveQueue(queueToUpdate);
} }
}); });
@ -251,26 +219,9 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
toRemove.forEach(q -> { toRemove.forEach(q -> {
Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q); Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q);
QueueId queueIdForRemove = queue.getId(); QueueId queueIdForRemove = queue.getId();
if (deviceProfileQueues.containsKey(queueIdForRemove)) {
Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, q);
if (foundQueue == null || queue.equals(foundQueue)) {
foundQueue = queueService.findQueueByTenantIdAndName(tenantId, MAIN);
}
QueueId newQueueId = foundQueue.getId();
deviceProfileQueues.get(queueIdForRemove).stream()
.peek(dp -> dp.setDefaultQueueId(newQueueId))
.forEach(this::saveDeviceProfile);
}
deleteQueue(tenantId, queueIdForRemove); deleteQueue(tenantId, queueIdForRemove);
}); });
}); });
} }
//TODO: remove after implementing TbDeviceProfileService
private void saveDeviceProfile(DeviceProfile deviceProfile) {
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), savedDeviceProfile.getId(), ComponentLifecycleEvent.UPDATED);
}
} }

31
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -195,22 +195,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public void createDefaultTenantProfiles() throws Exception { public void createDefaultTenantProfiles() throws Exception {
tenantProfileService.findOrCreateDefaultTenantProfile(TenantId.SYS_TENANT_ID); tenantProfileService.findOrCreateDefaultTenantProfile(TenantId.SYS_TENANT_ID);
TenantProfileData tenantProfileData = new TenantProfileData();
tenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration());
TenantProfile isolatedTbCoreProfile = new TenantProfile();
isolatedTbCoreProfile.setDefault(false);
isolatedTbCoreProfile.setName("Isolated TB Core");
isolatedTbCoreProfile.setDescription("Isolated TB Core tenant profile");
isolatedTbCoreProfile.setIsolatedTbCore(true);
isolatedTbCoreProfile.setIsolatedTbRuleEngine(false);
isolatedTbCoreProfile.setProfileData(tenantProfileData);
try {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreProfile);
} catch (DataValidationException e) {
log.warn(e.getMessage());
}
TenantProfileData isolatedRuleEngineTenantProfileData = new TenantProfileData(); TenantProfileData isolatedRuleEngineTenantProfileData = new TenantProfileData();
isolatedRuleEngineTenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration()); isolatedRuleEngineTenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration());
@ -239,7 +223,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
isolatedTbRuleEngineProfile.setDefault(false); isolatedTbRuleEngineProfile.setDefault(false);
isolatedTbRuleEngineProfile.setName("Isolated TB Rule Engine"); isolatedTbRuleEngineProfile.setName("Isolated TB Rule Engine");
isolatedTbRuleEngineProfile.setDescription("Isolated TB Rule Engine tenant profile"); isolatedTbRuleEngineProfile.setDescription("Isolated TB Rule Engine tenant profile");
isolatedTbRuleEngineProfile.setIsolatedTbCore(false);
isolatedTbRuleEngineProfile.setIsolatedTbRuleEngine(true); isolatedTbRuleEngineProfile.setIsolatedTbRuleEngine(true);
isolatedTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData); isolatedTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData);
@ -248,20 +231,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
} catch (DataValidationException e) { } catch (DataValidationException e) {
log.warn(e.getMessage()); log.warn(e.getMessage());
} }
TenantProfile isolatedTbCoreAndTbRuleEngineProfile = new TenantProfile();
isolatedTbCoreAndTbRuleEngineProfile.setDefault(false);
isolatedTbCoreAndTbRuleEngineProfile.setName("Isolated TB Core and TB Rule Engine");
isolatedTbCoreAndTbRuleEngineProfile.setDescription("Isolated TB Core and TB Rule Engine tenant profile");
isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbCore(true);
isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbRuleEngine(true);
isolatedTbCoreAndTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData);
try {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreAndTbRuleEngineProfile);
} catch (DataValidationException e) {
log.warn(e.getMessage());
}
} }
@Override @Override

4
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -589,10 +589,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
} catch (Exception e) { } catch (Exception e) {
} }
log.info("Updating device profiles...");
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", "schema_update_device_profile.sql");
loadSql(schemaUpdateFile, conn);
log.info("Updating schema settings..."); log.info("Updating schema settings...");
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;"); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;");
log.info("Schema updated."); log.info("Schema updated.");

44
application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java

@ -158,7 +158,6 @@ public class DefaultDataUpdateService implements DataUpdateService {
log.info("Updating data from version 3.3.4 to 3.4.0 ..."); log.info("Updating data from version 3.3.4 to 3.4.0 ...");
rateLimitsUpdater.updateEntities(); rateLimitsUpdater.updateEntities();
tenantsProfileQueueConfigurationUpdater.updateEntities(); tenantsProfileQueueConfigurationUpdater.updateEntities();
checkPointRuleNodesUpdater.updateEntities();
break; break;
default: default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
@ -629,47 +628,4 @@ public class DefaultDataUpdateService implements DataUpdateService {
return mainQueueConfiguration; return mainQueueConfiguration;
} }
private final PaginatedUpdater<String, RuleNode> checkPointRuleNodesUpdater =
new PaginatedUpdater<>() {
@Override
protected String getName() {
return "Checkpoint rule nodes updater";
}
@Override
protected boolean forceReportTotal() {
return true;
}
@Override
protected PageData<RuleNode> findEntities(String id, PageLink pageLink) {
return ruleChainService.findAllRuleNodesByType("org.thingsboard.rule.engine.flow.TbCheckpointNode", pageLink);
}
@Override
protected void updateEntity(RuleNode ruleNode) {
updateCheckPointRuleNodeConfiguration(ruleNode);
}
};
private void updateCheckPointRuleNodeConfiguration(RuleNode node) {
try {
ObjectNode configuration = (ObjectNode) node.getConfiguration();
JsonNode queueNameNode = configuration.remove("queueName");
if (queueNameNode != null) {
RuleChain ruleChain = this.ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, node.getRuleChainId());
TenantId tenantId = ruleChain.getTenantId();
Map<String, QueueId> queues =
queueService.findQueuesByTenantId(tenantId).stream().collect(Collectors.toMap(Queue::getName, Queue::getId));
String queueName = queueNameNode.asText();
QueueId queueId = queues.get(queueName);
configuration.put("queueId", queueId != null ? queueId.toString() : "");
ruleChainService.saveRuleNode(tenantId, node);
}
} catch (Exception e) {
log.error("Failed to update checkpoint rule node configuration name=["+node.getName()+"], id=["+ node.getId().getId() +"]", e);
}
}
} }

10
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java

@ -181,7 +181,7 @@ public class DefaultTbClusterService implements TbClusterService {
tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId()))); tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId())));
} }
} }
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueId(), tenantId, entityId); TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId);
log.trace("PUSHING msg: {} to:{}", tbMsg, tpi); log.trace("PUSHING msg: {} to:{}", tbMsg, tpi);
ToRuleEngineMsg msg = ToRuleEngineMsg.newBuilder() ToRuleEngineMsg msg = ToRuleEngineMsg.newBuilder()
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
@ -194,16 +194,16 @@ public class DefaultTbClusterService implements TbClusterService {
private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) { private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) {
if (deviceProfile != null) { if (deviceProfile != null) {
RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId(); RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId();
QueueId targetQueueId = deviceProfile.getDefaultQueueId(); String targetQueueName = deviceProfile.getDefaultQueueName();
boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId()); boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
boolean isQueueTransform = targetQueueId != null && !targetQueueId.equals(tbMsg.getQueueId()); boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
if (isRuleChainTransform && isQueueTransform) { if (isRuleChainTransform && isQueueTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueId); tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
} else if (isRuleChainTransform) { } else if (isRuleChainTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId); tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId);
} else if (isQueueTransform) { } else if (isQueueTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetQueueId); tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName);
} }
} }
return tbMsg; return tbMsg;

10
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java

@ -274,7 +274,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
final boolean timeout = !ctx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); final boolean timeout = !ctx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS);
TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getId(), timeout, ctx); TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, ctx);
if (timeout) { if (timeout) {
printFirstOrAll(configuration, ctx, ctx.getPendingMap(), "Timeout"); printFirstOrAll(configuration, ctx, ctx.getPendingMap(), "Timeout");
} }
@ -339,7 +339,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
new TbMsgPackCallback(id, tenantId, ctx); new TbMsgPackCallback(id, tenantId, ctx);
try { try {
if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) { if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) {
forwardToRuleEngineActor(configuration.getId(), tenantId, toRuleEngineMsg, callback); forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback);
} else { } else {
callback.onSuccess(); callback.onSuccess();
} }
@ -353,7 +353,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
log.info("{} to process [{}] messages", prefix, map.size()); log.info("{} to process [{}] messages", prefix, map.size());
for (Map.Entry<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> pending : map.entrySet()) { for (Map.Entry<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> pending : map.entrySet()) {
ToRuleEngineMsg tmp = pending.getValue().getValue(); ToRuleEngineMsg tmp = pending.getValue().getValue();
TbMsg tmpMsg = TbMsg.fromBytes(configuration.getId(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); TbMsg tmpMsg = TbMsg.fromBytes(configuration.getName(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY);
RuleNodeInfo ruleNodeInfo = ctx.getLastVisitedRuleNode(pending.getKey()); RuleNodeInfo ruleNodeInfo = ctx.getLastVisitedRuleNode(pending.getKey());
if (printAll) { if (printAll) {
log.trace("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); log.trace("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo);
@ -461,8 +461,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
partitionService.removeQueue(queueDeleteMsg); partitionService.removeQueue(queueDeleteMsg);
} }
private void forwardToRuleEngineActor(QueueId queueId, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) {
TbMsg tbMsg = TbMsg.fromBytes(queueId, toRuleEngineMsg.getTbMsg().toByteArray(), callback); TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback);
QueueToRuleEngineMsg msg; QueueToRuleEngineMsg msg;
ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList();
Set<String> relationTypes = null; Set<String> relationTypes = null;

2
application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java

@ -45,7 +45,7 @@ public class DefaultTenantRoutingInfoService implements TenantRoutingInfoService
Tenant tenant = tenantService.findTenantById(tenantId); Tenant tenant = tenantService.findTenantById(tenantId);
if (tenant != null) { if (tenant != null) {
TenantProfile tenantProfile = tenantProfileCache.get(tenant.getTenantProfileId()); TenantProfile tenantProfile = tenantProfileCache.get(tenant.getTenantProfileId());
return new TenantRoutingInfo(tenantId, tenantProfile.isIsolatedTbCore(), tenantProfile.isIsolatedTbRuleEngine()); return new TenantRoutingInfo(tenantId, tenantProfile.isIsolatedTbRuleEngine());
} else { } else {
throw new RuntimeException("Tenant not found!"); throw new RuntimeException("Tenant not found!");
} }

6
application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java

@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentMap;
public class TbRuleEngineProcessingResult { public class TbRuleEngineProcessingResult {
@Getter @Getter
private final QueueId queueId; private final String queueName;
@Getter @Getter
private final boolean success; private final boolean success;
@Getter @Getter
@ -37,8 +37,8 @@ public class TbRuleEngineProcessingResult {
@Getter @Getter
private final TbMsgPackProcessingContext ctx; private final TbMsgPackProcessingContext ctx;
public TbRuleEngineProcessingResult(QueueId queueId, boolean timeout, TbMsgPackProcessingContext ctx) { public TbRuleEngineProcessingResult(String queueName, boolean timeout, TbMsgPackProcessingContext ctx) {
this.queueId = queueId; this.queueName = queueName;
this.timeout = timeout; this.timeout = timeout;
this.ctx = ctx; this.ctx = ctx;
this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty(); this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty();

6
application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java

@ -125,7 +125,7 @@ public class TbRuleEngineProcessingStrategyFactory {
} }
log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size()); log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size());
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
} }
if (pauseBetweenRetries > 0) { if (pauseBetweenRetries > 0) {
try { try {
@ -164,10 +164,10 @@ public class TbRuleEngineProcessingStrategyFactory {
log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size()); log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size());
} }
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
} }
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
} }
return new TbRuleEngineProcessingDecision(true, null); return new TbRuleEngineProcessingDecision(true, null);
} }

1
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java

@ -53,7 +53,6 @@ public class DeviceProfileImportService extends BaseEntityImportService<DevicePr
deviceProfile.setDefaultDashboardId(idProvider.getInternalId(deviceProfile.getDefaultDashboardId())); deviceProfile.setDefaultDashboardId(idProvider.getInternalId(deviceProfile.getDefaultDashboardId()));
deviceProfile.setFirmwareId(getOldEntityField(old, DeviceProfile::getFirmwareId)); deviceProfile.setFirmwareId(getOldEntityField(old, DeviceProfile::getFirmwareId));
deviceProfile.setSoftwareId(getOldEntityField(old, DeviceProfile::getSoftwareId)); deviceProfile.setSoftwareId(getOldEntityField(old, DeviceProfile::getSoftwareId));
deviceProfile.setDefaultQueueId(getOldEntityField(old, DeviceProfile::getDefaultQueueId));
return deviceProfile; return deviceProfile;
} }

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

@ -148,7 +148,7 @@ ui:
# Help parameters # Help parameters
help: help:
# Base url for UI help assets # Base url for UI help assets
base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.3.4}" base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.4}"
database: database:
ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records

7
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -422,12 +422,6 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
} }
protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) { protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) {
return createDeviceProfile(name, deviceProfileTransportConfiguration, null);
}
protected DeviceProfile createDeviceProfile(String name,
DeviceProfileTransportConfiguration deviceProfileTransportConfiguration,
QueueId defaultQueueId) {
DeviceProfile deviceProfile = new DeviceProfile(); DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name); deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT); deviceProfile.setType(DeviceProfileType.DEFAULT);
@ -445,7 +439,6 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
deviceProfile.setProfileData(deviceProfileData); deviceProfile.setProfileData(deviceProfileData);
deviceProfile.setDefault(false); deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(null); deviceProfile.setDefaultRuleChainId(null);
deviceProfile.setDefaultQueueId(defaultQueueId);
return deviceProfile; return deviceProfile;
} }

57
application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java

@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
@ -49,15 +48,8 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
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.queue.ProcessingStrategy;
import org.thingsboard.server.common.data.queue.ProcessingStrategyType;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.queue.SubmitStrategy;
import org.thingsboard.server.common.data.queue.SubmitStrategyType;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.ArrayList; import java.util.ArrayList;
@ -389,55 +381,6 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
.andExpect(statusReason(containsString("Can't assign dashboard from different tenant!"))); .andExpect(statusReason(containsString("Can't assign dashboard from different tenant!")));
} }
@Test
public void testSaveDeviceProfileWithQueueFromDifferentTenant() throws Exception {
loginDifferentTenant();
loginSysAdmin();
TenantProfile tenantProfile = new TenantProfile();
tenantProfile.setDefault(false);
tenantProfile.setName("Isolated TB Rule Engine");
tenantProfile.setDescription("Isolated TB Rule Engine tenant profile");
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(true);
TenantProfileQueueConfiguration mainQueueConfiguration = new TenantProfileQueueConfiguration();
mainQueueConfiguration.setName("Main");
mainQueueConfiguration.setTopic("tb_rule_engine.main");
mainQueueConfiguration.setPollInterval(25);
mainQueueConfiguration.setPartitions(10);
mainQueueConfiguration.setConsumerPerPartition(true);
mainQueueConfiguration.setPackProcessingTimeout(2000);
SubmitStrategy mainQueueSubmitStrategy = new SubmitStrategy();
mainQueueSubmitStrategy.setType(SubmitStrategyType.BURST);
mainQueueSubmitStrategy.setBatchSize(1000);
mainQueueConfiguration.setSubmitStrategy(mainQueueSubmitStrategy);
ProcessingStrategy mainQueueProcessingStrategy = new ProcessingStrategy();
mainQueueProcessingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES);
mainQueueProcessingStrategy.setRetries(3);
mainQueueProcessingStrategy.setFailurePercentage(0);
mainQueueProcessingStrategy.setPauseBetweenRetries(3);
mainQueueProcessingStrategy.setMaxPauseBetweenRetries(3);
mainQueueConfiguration.setProcessingStrategy(mainQueueProcessingStrategy);
TenantProfileData profileData = tenantProfile.getProfileData();
profileData.setQueueConfiguration(Collections.singletonList(mainQueueConfiguration));
tenantProfile.setProfileData(profileData);
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
savedDifferentTenant.setTenantProfileId(savedTenantProfile.getId());
savedDifferentTenant = doPost("/api/tenant", savedDifferentTenant, Tenant.class);
loginDifferentTenant();
PageLink pageLink = new PageLink(1);
PageData<Queue> pageData = doGetTypedWithPageLink("/api/queues?serviceType=TB_RULE_ENGINE&",
new TypeReference<>() {}, pageLink);
Queue differentQueue = pageData.getData().get(0);
loginTenantAdmin();
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
deviceProfile.setDefaultQueueId(differentQueue.getId());
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Can't assign queue from different tenant!")));
}
@Test @Test
public void testSaveDeviceProfileWithFirmwareFromDifferentTenant() throws Exception { public void testSaveDeviceProfileWithFirmwareFromDifferentTenant() throws Exception {
loginDifferentTenant(); loginDifferentTenant();

18
application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java

@ -66,7 +66,6 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
Assert.assertEquals(tenantProfile.getDescription(), savedTenantProfile.getDescription()); Assert.assertEquals(tenantProfile.getDescription(), savedTenantProfile.getDescription());
Assert.assertEquals(tenantProfile.getProfileData(), savedTenantProfile.getProfileData()); Assert.assertEquals(tenantProfile.getProfileData(), savedTenantProfile.getProfileData());
Assert.assertEquals(tenantProfile.isDefault(), savedTenantProfile.isDefault()); Assert.assertEquals(tenantProfile.isDefault(), savedTenantProfile.isDefault());
Assert.assertEquals(tenantProfile.isIsolatedTbCore(), savedTenantProfile.isIsolatedTbCore());
Assert.assertEquals(tenantProfile.isIsolatedTbRuleEngine(), savedTenantProfile.isIsolatedTbRuleEngine()); Assert.assertEquals(tenantProfile.isIsolatedTbRuleEngine(), savedTenantProfile.isIsolatedTbRuleEngine());
testBroadcastEntityStateChangeEventTimeManyTimeTenantProfile(savedTenantProfile, ComponentLifecycleEvent.CREATED, 1); testBroadcastEntityStateChangeEventTimeManyTimeTenantProfile(savedTenantProfile, ComponentLifecycleEvent.CREATED, 1);
@ -182,22 +181,6 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
testBroadcastEntityStateChangeEventNeverTenantProfile(); testBroadcastEntityStateChangeEventNeverTenantProfile();
} }
@Test
public void testSaveSameTenantProfileWithDifferentIsolatedTbCore() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
Mockito.reset(tbClusterService);
savedTenantProfile.setIsolatedTbCore(true);
doPost("/api/tenantProfile", savedTenantProfile)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Can't update isolatedTbCore property")));
testBroadcastEntityStateChangeEventNeverTenantProfile();
}
@Test @Test
public void testDeleteTenantProfileWithExistingTenant() throws Exception { public void testDeleteTenantProfileWithExistingTenant() throws Exception {
loginSysAdmin(); loginSysAdmin();
@ -352,7 +335,6 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController
tenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration()); tenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration());
tenantProfile.setProfileData(tenantProfileData); tenantProfile.setProfileData(tenantProfileData);
tenantProfile.setDefault(false); tenantProfile.setDefault(false);
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(false); tenantProfile.setIsolatedTbRuleEngine(false);
return tenantProfile; return tenantProfile;
} }

7
application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java

@ -163,7 +163,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
private Tenant savedTenant; private Tenant savedTenant;
private TenantId tenantId; private TenantId tenantId;
private User tenantAdmin; private User tenantAdmin;
private QueueId defaultQueueId;
private DeviceProfile thermostatDeviceProfile; private DeviceProfile thermostatDeviceProfile;
@ -186,8 +185,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
tenantId = savedTenant.getId(); tenantId = savedTenant.getId();
Assert.assertNotNull(savedTenant); Assert.assertNotNull(savedTenant);
defaultQueueId = getRandomQueueId();
tenantAdmin = new User(); tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId()); tenantAdmin.setTenantId(savedTenant.getId());
@ -378,7 +375,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
@Test @Test
public void testDeviceProfiles() throws Exception { public void testDeviceProfiles() throws Exception {
// 1 // 1
DeviceProfile deviceProfile = this.createDeviceProfile("ONE_MORE_DEVICE_PROFILE", null, defaultQueueId); DeviceProfile deviceProfile = this.createDeviceProfile("ONE_MORE_DEVICE_PROFILE", null);
extendDeviceProfileData(deviceProfile); extendDeviceProfileData(deviceProfile);
edgeImitator.expectMessageAmount(1); edgeImitator.expectMessageAmount(1);
deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
@ -389,8 +386,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, deviceProfileUpdateMsg.getMsgType()); Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, deviceProfileUpdateMsg.getMsgType());
Assert.assertEquals(deviceProfileUpdateMsg.getIdMSB(), deviceProfile.getUuidId().getMostSignificantBits()); Assert.assertEquals(deviceProfileUpdateMsg.getIdMSB(), deviceProfile.getUuidId().getMostSignificantBits());
Assert.assertEquals(deviceProfileUpdateMsg.getIdLSB(), deviceProfile.getUuidId().getLeastSignificantBits()); Assert.assertEquals(deviceProfileUpdateMsg.getIdLSB(), deviceProfile.getUuidId().getLeastSignificantBits());
Assert.assertEquals(defaultQueueId.getId().getMostSignificantBits(), deviceProfileUpdateMsg.getDefaultQueueIdMSB());
Assert.assertEquals(defaultQueueId.getId().getLeastSignificantBits(), deviceProfileUpdateMsg.getDefaultQueueIdLSB());
// 2 // 2
edgeImitator.expectMessageAmount(1); edgeImitator.expectMessageAmount(1);

22
application/src/test/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructorTest.java

@ -23,53 +23,37 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto; import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleNodeProto; import org.thingsboard.server.gen.edge.v1.RuleNodeProto;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadataConstructorV333;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static org.mockito.Mockito.mock;
@Slf4j @Slf4j
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class RuleChainMsgConstructorTest { public class RuleChainMsgConstructorTest {
private RuleChainMsgConstructor constructor; private RuleChainMsgConstructor constructor;
private QueueService queueService;
private TenantId tenantId; private TenantId tenantId;
private String queueId = "af588000-6c7c-11ec-bafd-c9a47a5c8d99";
@Before @Before
public void setup() { public void setup() {
queueService = mock(QueueService.class); constructor = new RuleChainMsgConstructor();
constructor = new RuleChainMsgConstructor(queueService);
tenantId = new TenantId(UUID.randomUUID()); tenantId = new TenantId(UUID.randomUUID());
Queue queue = new Queue();
queue.setName("HighPriority");
Mockito.when(queueService.findQueueById(tenantId, new QueueId(UUID.fromString(queueId)))).thenReturn(queue);
} }
@Test @Test
@ -88,7 +72,7 @@ public class RuleChainMsgConstructorTest {
assertCheckpointRuleNodeConfiguration( assertCheckpointRuleNodeConfiguration(
ruleChainMetadataUpdateMsg.getNodesList(), ruleChainMetadataUpdateMsg.getNodesList(),
"{\"queueId\":\"" + queueId + "\"}"); "{\"queueName\":\"HighPriority\"}");
} }
@Test @Test
@ -345,7 +329,7 @@ public class RuleChainMsgConstructorTest {
return createRuleNode(ruleChainId, return createRuleNode(ruleChainId,
"org.thingsboard.rule.engine.flow.TbCheckpointNode", "org.thingsboard.rule.engine.flow.TbCheckpointNode",
"Checkpoint node", "Checkpoint node",
JacksonUtil.OBJECT_MAPPER.readTree("{\"queueId\":\"" + queueId + "\"}"), JacksonUtil.OBJECT_MAPPER.readTree("{\"queueName\":\"HighPriority\"}"),
JacksonUtil.OBJECT_MAPPER.readTree("{\"description\":\"\",\"layoutX\":178,\"layoutY\":647}")); JacksonUtil.OBJECT_MAPPER.readTree("{\"description\":\"\",\"layoutX\":178,\"layoutY\":647}"));
} }

95
application/src/test/java/org/thingsboard/server/transport/coap/attributes/AbstractCoapAttributesIntegrationTest.java

@ -46,11 +46,11 @@ import org.thingsboard.server.transport.coap.CoapTestClient;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -235,25 +235,37 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
CoapTestCallback callbackCoap = new CoapTestCallback(1); CoapTestCallback callbackCoap = new CoapTestCallback(1);
CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap); CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap);
callbackCoap.getLatch().await(3, TimeUnit.SECONDS); String awaitAlias = "await Json Test Subscribe To AttributesUpdates (client.getObserveRelation)";
await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
0 == callbackCoap.getObserve().intValue());
if (emptyCurrentStateNotification) { if (emptyCurrentStateNotification) {
validateUpdateAttributesJsonResponse(callbackCoap, "{}", 0); validateUpdateAttributesJsonResponse(callbackCoap, "{}");
} else { } else {
validateUpdateAttributesJsonResponse(callbackCoap, SHARED_ATTRIBUTES_PAYLOAD_ON_CURRENT_STATE_NOTIFICATION, 0); validateUpdateAttributesJsonResponse(callbackCoap, SHARED_ATTRIBUTES_PAYLOAD_ON_CURRENT_STATE_NOTIFICATION);
} }
CountDownLatch latch = new CountDownLatch(1); int expectedObserveForAttributesUpdate = callbackCoap.getObserve().intValue() + 1;
int expectedObserveCnt = callbackCoap.getObserve().intValue() + 1;
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
latch.await(3, TimeUnit.SECONDS); awaitAlias = "await Json Test Subscribe To AttributesUpdates (add attributes)";
validateUpdateAttributesJsonResponse(callbackCoap, SHARED_ATTRIBUTES_PAYLOAD, expectedObserveCnt); await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
latch = new CountDownLatch(1); .until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
int expectedObserveBeforeDeleteCnt = callbackCoap.getObserve().intValue() + 1; callbackCoap.getObserve() != null &&
expectedObserveForAttributesUpdate == callbackCoap.getObserve().intValue());
validateUpdateAttributesJsonResponse(callbackCoap, SHARED_ATTRIBUTES_PAYLOAD);
int expectedObserveForAttributesDelete = callbackCoap.getObserve().intValue() + 1;
doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=sharedJson", String.class); doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=sharedJson", String.class);
latch.await(3, TimeUnit.SECONDS); awaitAlias = "await Json Test Subscribe To AttributesUpdates (deleted attributes)";
validateUpdateAttributesJsonResponse(callbackCoap, SHARED_ATTRIBUTES_DELETED_RESPONSE, expectedObserveBeforeDeleteCnt); await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
expectedObserveForAttributesDelete == callbackCoap.getObserve().intValue());
validateUpdateAttributesJsonResponse(callbackCoap, SHARED_ATTRIBUTES_DELETED_RESPONSE);
observeRelation.proactiveCancel(); observeRelation.proactiveCancel();
assertTrue(observeRelation.isCanceled()); assertTrue(observeRelation.isCanceled());
@ -269,8 +281,13 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
client = new CoapTestClient(accessToken, FeatureType.ATTRIBUTES); client = new CoapTestClient(accessToken, FeatureType.ATTRIBUTES);
CoapTestCallback callbackCoap = new CoapTestCallback(1); CoapTestCallback callbackCoap = new CoapTestCallback(1);
String awaitAlias = "await Proto Test Subscribe To Attributes Updates (add attributes)";
CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap); CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap);
callbackCoap.getLatch().await(3, TimeUnit.SECONDS); await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
0 == callbackCoap.getObserve().intValue());
if (emptyCurrentStateNotification) { if (emptyCurrentStateNotification) {
validateEmptyCurrentStateAttributesProtoResponse(callbackCoap); validateEmptyCurrentStateAttributesProtoResponse(callbackCoap);
@ -278,17 +295,25 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
validateCurrentStateAttributesProtoResponse(callbackCoap); validateCurrentStateAttributesProtoResponse(callbackCoap);
} }
CountDownLatch latch = new CountDownLatch(1); int expectedObserveForAttributesUpdate = callbackCoap.getObserve().intValue() + 1;
int expectedObserveCnt = callbackCoap.getObserve().intValue() + 1;
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
latch.await(3, TimeUnit.SECONDS); awaitAlias = "await Proto Test Subscribe To Attributes Updates (add attributes)";
validateUpdateProtoAttributesResponse(callbackCoap, expectedObserveCnt); await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
latch = new CountDownLatch(1); .until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
int expectedObserveBeforeDeleteCnt = callbackCoap.getObserve().intValue() + 1; callbackCoap.getObserve() != null &&
expectedObserveForAttributesUpdate == callbackCoap.getObserve().intValue());
validateUpdateProtoAttributesResponse(callbackCoap, expectedObserveForAttributesUpdate);
int expectedObserveForAttributesDelete = callbackCoap.getObserve().intValue() + 1;
doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=sharedJson", String.class); doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=sharedJson", String.class);
latch.await(3, TimeUnit.SECONDS); awaitAlias = "await Proto Test Subscribe To Attributes Updates (deleted attributes)";
validateDeleteProtoAttributesResponse(callbackCoap, expectedObserveBeforeDeleteCnt); await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
expectedObserveForAttributesDelete == callbackCoap.getObserve().intValue());
validateDeleteProtoAttributesResponse(callbackCoap, expectedObserveForAttributesDelete);
observeRelation.proactiveCancel(); observeRelation.proactiveCancel();
assertTrue(observeRelation.isCanceled()); assertTrue(observeRelation.isCanceled());
@ -314,27 +339,18 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos));
} }
protected void validateUpdateAttributesJsonResponse(CoapTestCallback callback, String expectedResponse, int expectedObserveCnt) { protected void validateUpdateAttributesJsonResponse(CoapTestCallback callback, String expectedResponse) {
assertNotNull(callback.getPayloadBytes()); assertNotNull(callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(expectedObserveCnt, callback.getObserve().intValue());
String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8);
assertEquals(JacksonUtil.toJsonNode(expectedResponse), JacksonUtil.toJsonNode(response)); assertEquals(JacksonUtil.toJsonNode(expectedResponse), JacksonUtil.toJsonNode(response));
} }
protected void validateEmptyCurrentStateAttributesProtoResponse(CoapTestCallback callback) throws InvalidProtocolBufferException { protected void validateEmptyCurrentStateAttributesProtoResponse(CoapTestCallback callback) throws InvalidProtocolBufferException {
assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes()); assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(0, callback.getObserve().intValue());
} }
protected void validateCurrentStateAttributesProtoResponse(CoapTestCallback callback) throws InvalidProtocolBufferException { protected void validateCurrentStateAttributesProtoResponse(CoapTestCallback callback) throws InvalidProtocolBufferException {
assertNotNull(callback.getPayloadBytes()); assertNotNull(callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(0, callback.getObserve().intValue());
TransportProtos.AttributeUpdateNotificationMsg.Builder expectedCurrentStateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); TransportProtos.AttributeUpdateNotificationMsg.Builder expectedCurrentStateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("sharedStr", "value", TransportProtos.KeyValueType.STRING_V); TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("sharedStr", "value", TransportProtos.KeyValueType.STRING_V);
TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("sharedBool", "false", TransportProtos.KeyValueType.BOOLEAN_V); TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("sharedBool", "false", TransportProtos.KeyValueType.BOOLEAN_V);
@ -359,9 +375,6 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
protected void validateUpdateProtoAttributesResponse(CoapTestCallback callback, int expectedObserveCnt) throws InvalidProtocolBufferException { protected void validateUpdateProtoAttributesResponse(CoapTestCallback callback, int expectedObserveCnt) throws InvalidProtocolBufferException {
assertNotNull(callback.getPayloadBytes()); assertNotNull(callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(expectedObserveCnt, callback.getObserve().intValue());
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList("shared"); List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList("shared");
attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList);
@ -378,9 +391,6 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
protected void validateDeleteProtoAttributesResponse(CoapTestCallback callback, int expectedObserveCnt) throws InvalidProtocolBufferException { protected void validateDeleteProtoAttributesResponse(CoapTestCallback callback, int expectedObserveCnt) throws InvalidProtocolBufferException {
assertNotNull(callback.getPayloadBytes()); assertNotNull(callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(expectedObserveCnt, callback.getObserve().intValue());
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder();
attributeUpdateNotificationMsgBuilder.addSharedDeleted("sharedJson"); attributeUpdateNotificationMsgBuilder.addSharedDeleted("sharedJson");
@ -395,9 +405,10 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
Awaitility.await("awaitClientAfterCancelObserve") Awaitility.await("awaitClientAfterCancelObserve")
.pollInterval(10, TimeUnit.MILLISECONDS) .pollInterval(10, TimeUnit.MILLISECONDS)
.atMost(5, TimeUnit.SECONDS) .atMost(5, TimeUnit.SECONDS)
.until(()->{ .until(() -> {
log.trace("awaiting defaultTransportService.sessions is empty"); log.trace("awaiting defaultTransportService.sessions is empty");
return defaultTransportService.sessions.isEmpty();}); return defaultTransportService.sessions.isEmpty();
});
} }
private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() { private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() {

62
application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java

@ -43,6 +43,7 @@ import org.thingsboard.server.transport.coap.CoapTestClient;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -75,14 +76,23 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
CoapTestCallback callbackCoap = new TestCoapCallbackForRPC(client, 1, true, protobuf); CoapTestCallback callbackCoap = new TestCoapCallbackForRPC(client, 1, true, protobuf);
CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap); CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap);
callbackCoap.getLatch().await(3, TimeUnit.SECONDS); String awaitAlias = "await One Way Rpc (client.getObserveRelation)";
await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.VALID.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
0 == callbackCoap.getObserve().intValue());
validateCurrentStateNotification(callbackCoap); validateCurrentStateNotification(callbackCoap);
int expectedObserveCountAfterGpioRequest = callbackCoap.getObserve().intValue() + 1;
CountDownLatch latch = new CountDownLatch(1);
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
String deviceId = savedDevice.getId().getId().toString(); String deviceId = savedDevice.getId().getId().toString();
String result = doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk()); String result = doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk());
latch.await(3, TimeUnit.SECONDS); awaitAlias = "await One Way Rpc setGpio(method, params, value)";
await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
expectedObserveCountAfterGpioRequest == callbackCoap.getObserve().intValue());
validateOneWayStateChangedNotification(callbackCoap, result); validateOneWayStateChangedNotification(callbackCoap, result);
observeRelation.proactiveCancel(); observeRelation.proactiveCancel();
@ -94,23 +104,36 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
CoapTestCallback callbackCoap = new TestCoapCallbackForRPC(client, 1, false, protobuf); CoapTestCallback callbackCoap = new TestCoapCallbackForRPC(client, 1, false, protobuf);
CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap); CoapObserveRelation observeRelation = client.getObserveRelation(callbackCoap);
callbackCoap.getLatch().await(3, TimeUnit.SECONDS); String awaitAlias = "await Two Way Rpc (client.getObserveRelation)";
await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.VALID.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
0 == callbackCoap.getObserve().intValue());
validateCurrentStateNotification(callbackCoap); validateCurrentStateNotification(callbackCoap);
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
String deviceId = savedDevice.getId().getId().toString(); String deviceId = savedDevice.getId().getId().toString();
int expectedObserveCountAfterGpioRequest1 = callbackCoap.getObserve().intValue() + 1;
String actualResult = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); String actualResult = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
callbackCoap.getLatch().await(3, TimeUnit.SECONDS); awaitAlias = "await Two Way Rpc (setGpio(method, params, value) first";
await(awaitAlias)
validateTwoWayStateChangedNotification(callbackCoap, 1, expectedResponseResult, actualResult); .atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
CountDownLatch latch = new CountDownLatch(1); callbackCoap.getObserve() != null &&
expectedObserveCountAfterGpioRequest1 == callbackCoap.getObserve().intValue());
validateTwoWayStateChangedNotification(callbackCoap, expectedResponseResult, actualResult);
int expectedObserveCountAfterGpioRequest2 = callbackCoap.getObserve().intValue() + 1;
actualResult = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); actualResult = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
callbackCoap.getLatch().await(3, TimeUnit.SECONDS); awaitAlias = "await Two Way Rpc (setGpio(method, params, value) first";
await(awaitAlias)
.atMost(10, TimeUnit.SECONDS)
.until(() -> CoAP.ResponseCode.CONTENT.equals(callbackCoap.getResponseCode()) &&
callbackCoap.getObserve() != null &&
expectedObserveCountAfterGpioRequest2 == callbackCoap.getObserve().intValue());
validateTwoWayStateChangedNotification(callbackCoap, 2, expectedResponseResult, actualResult); validateTwoWayStateChangedNotification(callbackCoap, expectedResponseResult, actualResult);
observeRelation.proactiveCancel(); observeRelation.proactiveCancel();
assertTrue(observeRelation.isCanceled()); assertTrue(observeRelation.isCanceled());
@ -184,25 +207,16 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
private void validateCurrentStateNotification(CoapTestCallback callback) { private void validateCurrentStateNotification(CoapTestCallback callback) {
assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes()); assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(callback.getResponseCode(), CoAP.ResponseCode.VALID);
assertEquals(0, callback.getObserve().intValue());
} }
private void validateOneWayStateChangedNotification(CoapTestCallback callback, String result) { private void validateOneWayStateChangedNotification(CoapTestCallback callback, String result) {
assertTrue(StringUtils.isEmpty(result)); assertTrue(StringUtils.isEmpty(result));
assertNotNull(callback.getPayloadBytes()); assertNotNull(callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(1, callback.getObserve().intValue());
} }
private void validateTwoWayStateChangedNotification(CoapTestCallback callback, int expectedObserveNumber, String expectedResult, String actualResult) { private void validateTwoWayStateChangedNotification(CoapTestCallback callback, String expectedResult, String actualResult) {
assertEquals(expectedResult, actualResult); assertEquals(expectedResult, actualResult);
assertNotNull(callback.getPayloadBytes()); assertNotNull(callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(expectedObserveNumber, callback.getObserve().intValue());
} }
protected class TestCoapCallbackForRPC extends CoapTestCallback { protected class TestCoapCallbackForRPC extends CoapTestCallback {

1
application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcJsonIntegrationTest.java

@ -52,5 +52,4 @@ public class CoapServerSideRpcJsonIntegrationTest extends AbstractCoapServerSide
public void testServerCoapTwoWayRpc() throws Exception { public void testServerCoapTwoWayRpc() throws Exception {
processTwoWayRpcTest("{\"value1\":\"A\",\"value2\":\"B\"}", false); processTwoWayRpcTest("{\"value1\":\"A\",\"value2\":\"B\"}", false);
} }
} }

6
application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java

@ -196,7 +196,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M
device.getId().getId().toString(); device.getId().getId().toString();
lwM2MTestClient.start(isStartLw); lwM2MTestClient.start(isStartLw);
await(awaitAlias) await(awaitAlias)
.atMost(1000, TimeUnit.MILLISECONDS) .atMost(5000, TimeUnit.MILLISECONDS)
.until(() -> finishState.equals(lwM2MTestClient.getClientState())); .until(() -> finishState.equals(lwM2MTestClient.getClientState()));
Assert.assertEquals(expectedStatuses, lwM2MTestClient.getClientStates()); Assert.assertEquals(expectedStatuses, lwM2MTestClient.getClientStates());
} }
@ -234,7 +234,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M
String deviceId = device.getId().getId().toString(); String deviceId = device.getId().getId().toString();
lwM2MTestClient.start(true); lwM2MTestClient.start(true);
await(awaitAlias) await(awaitAlias)
.atMost(1000, TimeUnit.MILLISECONDS) .atMost(5000, TimeUnit.MILLISECONDS)
.until(() -> ON_REGISTRATION_SUCCESS.equals(lwM2MTestClient.getClientState())); .until(() -> ON_REGISTRATION_SUCCESS.equals(lwM2MTestClient.getClientState()));
Assert.assertEquals(expectedStatusesLwm2m, lwM2MTestClient.getClientStates()); Assert.assertEquals(expectedStatusesLwm2m, lwM2MTestClient.getClientStates());
@ -246,7 +246,7 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M
expectedStatusesBs.add(ON_DEREGISTRATION_STARTED); expectedStatusesBs.add(ON_DEREGISTRATION_STARTED);
expectedStatusesBs.add(ON_DEREGISTRATION_SUCCESS); expectedStatusesBs.add(ON_DEREGISTRATION_SUCCESS);
await(awaitAlias) await(awaitAlias)
.atMost(1000, TimeUnit.MILLISECONDS) .atMost(5000, TimeUnit.MILLISECONDS)
.until(() -> ON_REGISTRATION_SUCCESS.equals(lwM2MTestClient.getClientState())); .until(() -> ON_REGISTRATION_SUCCESS.equals(lwM2MTestClient.getClientState()));
Assert.assertEquals(expectedStatusesBs, lwM2MTestClient.getClientStates()); Assert.assertEquals(expectedStatusesBs, lwM2MTestClient.getClientStates());
} }

1
common/cluster-api/src/main/proto/queue.proto

@ -273,7 +273,6 @@ message GetTenantRoutingInfoRequestMsg {
} }
message GetTenantRoutingInfoResponseMsg { message GetTenantRoutingInfoResponseMsg {
bool isolatedTbCore = 1;
bool isolatedTbRuleEngine = 2; bool isolatedTbRuleEngine = 2;
} }

16
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java

@ -74,12 +74,11 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
private RuleChainId defaultRuleChainId; private RuleChainId defaultRuleChainId;
@ApiModelProperty(position = 6, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.") @ApiModelProperty(position = 6, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.")
private DashboardId defaultDashboardId; private DashboardId defaultDashboardId;
@NoXss @NoXss
@ApiModelProperty(position = 8, value = "Reference to the rule engine queue. " + @ApiModelProperty(position = 8, value = "Rule engine queue name. " +
"If present, the specified queue will be used to store all unprocessed messages related to device, including telemetry, attribute updates, etc. " + "If present, the specified queue will be used to store all unprocessed messages related to device, including telemetry, attribute updates, etc. " +
"Otherwise, the 'Main' queue will be used to store those messages.") "Otherwise, the 'Main' queue will be used to store those messages.")
private QueueId defaultQueueId;
private String defaultQueueName; private String defaultQueueName;
@Valid @Valid
private transient DeviceProfileData profileData; private transient DeviceProfileData profileData;
@ -113,7 +112,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
this.isDefault = deviceProfile.isDefault(); this.isDefault = deviceProfile.isDefault();
this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId(); this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId();
this.defaultDashboardId = deviceProfile.getDefaultDashboardId(); this.defaultDashboardId = deviceProfile.getDefaultDashboardId();
this.defaultQueueId = deviceProfile.getDefaultQueueId(); this.defaultQueueName = deviceProfile.getDefaultQueueName();
this.setProfileData(deviceProfile.getProfileData()); this.setProfileData(deviceProfile.getProfileData());
this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
this.firmwareId = deviceProfile.getFirmwareId(); this.firmwareId = deviceProfile.getFirmwareId();
@ -174,13 +173,4 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
} }
} }
@JsonIgnore
public String getDefaultQueueName() {
return defaultQueueName;
}
@JsonProperty
public void setDefaultQueueName(String defaultQueueName) {
this.defaultQueueName = defaultQueueName;
}
} }

8
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java

@ -53,13 +53,10 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H
private String description; private String description;
@ApiModelProperty(position = 5, value = "Default Tenant profile to be used.", example = "true") @ApiModelProperty(position = 5, value = "Default Tenant profile to be used.", example = "true")
private boolean isDefault; private boolean isDefault;
@ApiModelProperty(position = 6, value = "If enabled, will push all messages related to this tenant and processed by core platform services into separate queue. " + @ApiModelProperty(position = 6, value = "If enabled, will push all messages related to this tenant and processed by the rule engine into separate queue. " +
"Useful for complex microservices deployments, to isolate processing of the data for specific tenants", example = "true")
private boolean isolatedTbCore;
@ApiModelProperty(position = 7, value = "If enabled, will push all messages related to this tenant and processed by the rule engine into separate queue. " +
"Useful for complex microservices deployments, to isolate processing of the data for specific tenants", example = "true") "Useful for complex microservices deployments, to isolate processing of the data for specific tenants", example = "true")
private boolean isolatedTbRuleEngine; private boolean isolatedTbRuleEngine;
@ApiModelProperty(position = 8, value = "Complex JSON object that contains profile settings: queue configs, max devices, max assets, rate limits, etc.") @ApiModelProperty(position = 7, value = "Complex JSON object that contains profile settings: queue configs, max devices, max assets, rate limits, etc.")
private transient TenantProfileData profileData; private transient TenantProfileData profileData;
@JsonIgnore @JsonIgnore
private byte[] profileDataBytes; private byte[] profileDataBytes;
@ -77,7 +74,6 @@ public class TenantProfile extends SearchTextBased<TenantProfileId> implements H
this.name = tenantProfile.getName(); this.name = tenantProfile.getName();
this.description = tenantProfile.getDescription(); this.description = tenantProfile.getDescription();
this.isDefault = tenantProfile.isDefault(); this.isDefault = tenantProfile.isDefault();
this.isolatedTbCore = tenantProfile.isIsolatedTbCore();
this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine(); this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine();
this.setProfileData(tenantProfile.getProfileData()); this.setProfileData(tenantProfile.getProfileData());
} }

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

@ -216,8 +216,6 @@ message DeviceProfileUpdateMsg {
bytes profileDataBytes = 13; bytes profileDataBytes = 13;
optional string provisionDeviceKey = 14; optional string provisionDeviceKey = 14;
optional bytes image = 15; optional bytes image = 15;
int64 defaultQueueIdMSB = 16;
int64 defaultQueueIdLSB = 17;
} }
message DeviceCredentialsUpdateMsg { message DeviceCredentialsUpdateMsg {

48
common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java

@ -43,7 +43,7 @@ import java.util.UUID;
@Slf4j @Slf4j
public final class TbMsg implements Serializable { public final class TbMsg implements Serializable {
private final QueueId queueId; private final String queueName;
private final UUID id; private final UUID id;
private final long ts; private final long ts;
private final String type; private final String type;
@ -67,12 +67,12 @@ public final class TbMsg implements Serializable {
return ctx.getAndIncrementRuleNodeCounter(); return ctx.getAndIncrementRuleNodeCounter();
} }
public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return newMsg(queueId, type, originator, null, metaData, data, ruleChainId, ruleNodeId); return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId);
} }
public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(queueId, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY);
} }
@ -87,12 +87,12 @@ public final class TbMsg implements Serializable {
// REALLY NEW MSG // REALLY NEW MSG
public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data) { public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return newMsg(queueId, type, originator, null, metaData, data); return newMsg(queueName, type, originator, null, metaData, data);
} }
public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
return new TbMsg(queueId, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY);
} }
@ -118,40 +118,40 @@ public final class TbMsg implements Serializable {
} }
public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return new TbMsg(tbMsg.queueId, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType,
data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback);
} }
public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) { public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) {
return new TbMsg(tbMsg.queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback());
} }
public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) { public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) {
return new TbMsg(tbMsg.queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback());
} }
public static TbMsg transformMsg(TbMsg tbMsg, QueueId queueId) { public static TbMsg transformMsg(TbMsg tbMsg, String queueName) {
return new TbMsg(queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback()); tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback());
} }
public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, QueueId queueId) { public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, String queueName) {
return new TbMsg(queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback());
} }
//used for enqueueForTellNext //used for enqueueForTellNext
public static TbMsg newMsg(TbMsg tbMsg, QueueId queueId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { public static TbMsg newMsg(TbMsg tbMsg, String queueName, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
return new TbMsg(queueId, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(), return new TbMsg(queueName, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(),
tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ctx.copy(), TbMsgCallback.EMPTY); tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ctx.copy(), TbMsgCallback.EMPTY);
} }
private TbMsg(QueueId queueId, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data,
RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) {
this.id = id; this.id = id;
this.queueId = queueId; this.queueName = queueName;
if (ts > 0) { if (ts > 0) {
this.ts = ts; this.ts = ts;
} else { } else {
@ -220,7 +220,7 @@ public final class TbMsg implements Serializable {
return builder.build().toByteArray(); return builder.build().toByteArray();
} }
public static TbMsg fromBytes(QueueId queueId, byte[] data, TbMsgCallback callback) { public static TbMsg fromBytes(String queueName, byte[] data, TbMsgCallback callback) {
try { try {
MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data); MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data);
TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap());
@ -247,7 +247,7 @@ public final class TbMsg implements Serializable {
} }
TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()];
return new TbMsg(queueId, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId,
metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, ctx, callback); metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, ctx, callback);
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
throw new IllegalStateException("Could not parse protobuf for TbMsg", e); throw new IllegalStateException("Could not parse protobuf for TbMsg", e);
@ -259,12 +259,12 @@ public final class TbMsg implements Serializable {
} }
public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) {
return new TbMsg(this.queueId, msgId, this.ts, this.type, this.originator, this.customerId, return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId,
this.metaData, this.dataType, this.data, ruleChainId, null, this.ctx, callback); this.metaData, this.dataType, this.data, ruleChainId, null, this.ctx, callback);
} }
public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) {
return new TbMsg(this.queueId, msgId, this.ts, this.type, this.originator, this.customerId, return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId,
this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback); this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback);
} }

38
common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java

@ -68,8 +68,6 @@ public class HashPartitionService implements PartitionService {
private final TenantRoutingInfoService tenantRoutingInfoService; private final TenantRoutingInfoService tenantRoutingInfoService;
private final QueueRoutingInfoService queueRoutingInfoService; private final QueueRoutingInfoService queueRoutingInfoService;
private final ConcurrentMap<QueueId, QueueRoutingInfo> queuesById = new ConcurrentHashMap<>();
private ConcurrentMap<QueueKey, List<Integer>> myPartitions = new ConcurrentHashMap<>(); private ConcurrentMap<QueueKey, List<Integer>> myPartitions = new ConcurrentHashMap<>();
private final ConcurrentMap<QueueKey, String> partitionTopicsMap = new ConcurrentHashMap<>(); private final ConcurrentMap<QueueKey, String> partitionTopicsMap = new ConcurrentHashMap<>();
@ -121,7 +119,6 @@ public class HashPartitionService implements PartitionService {
QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queue); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queue);
partitionTopicsMap.put(queueKey, queue.getQueueTopic()); partitionTopicsMap.put(queueKey, queue.getQueueTopic());
partitionSizesMap.put(queueKey, queue.getPartitions()); partitionSizesMap.put(queueKey, queue.getPartitions());
queuesById.put(queue.getQueueId(), queue);
}); });
} }
@ -165,8 +162,6 @@ public class HashPartitionService implements PartitionService {
public void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { public void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) {
TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB()));
QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName(), tenantId); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName(), tenantId);
QueueRoutingInfo queue = new QueueRoutingInfo(queueUpdateMsg);
queuesById.put(queue.getQueueId(), queue);
partitionTopicsMap.put(queueKey, queueUpdateMsg.getQueueTopic()); partitionTopicsMap.put(queueKey, queueUpdateMsg.getQueueTopic());
partitionSizesMap.put(queueKey, queueUpdateMsg.getPartitions()); partitionSizesMap.put(queueKey, queueUpdateMsg.getPartitions());
myPartitions.remove(queueKey); myPartitions.remove(queueKey);
@ -176,7 +171,6 @@ public class HashPartitionService implements PartitionService {
public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) {
TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB()));
QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId);
queuesById.remove(new QueueId(new UUID(queueDeleteMsg.getQueueIdMSB(), queueDeleteMsg.getQueueIdLSB())));
myPartitions.remove(queueKey); myPartitions.remove(queueKey);
partitionTopicsMap.remove(queueKey); partitionTopicsMap.remove(queueKey);
partitionSizesMap.remove(queueKey); partitionSizesMap.remove(queueKey);
@ -185,9 +179,7 @@ public class HashPartitionService implements PartitionService {
} }
@Override @Override
@Deprecated public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) {
public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId, String queueName) {
log.warn("This method is deprecated and will be removed!!!");
TenantId isolatedOrSystemTenantId = getIsolatedOrSystemTenantId(serviceType, tenantId); TenantId isolatedOrSystemTenantId = getIsolatedOrSystemTenantId(serviceType, tenantId);
QueueKey queueKey = new QueueKey(serviceType, queueName, isolatedOrSystemTenantId); QueueKey queueKey = new QueueKey(serviceType, queueName, isolatedOrSystemTenantId);
if (!partitionSizesMap.containsKey(queueKey)) { if (!partitionSizesMap.containsKey(queueKey)) {
@ -201,32 +193,6 @@ public class HashPartitionService implements PartitionService {
return resolve(serviceType, null, tenantId, entityId); return resolve(serviceType, null, tenantId, entityId);
} }
@Override
public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) {
QueueKey queueKey;
if (queueId == null) {
queueKey = getMainQueueKey(serviceType, tenantId);
} else {
QueueRoutingInfo queueRoutingInfo = queuesById.get(queueId);
if (queueRoutingInfo == null) {
log.debug("Queue was removed but still used in CheckPoint rule node. [{}][{}]", tenantId, entityId);
queueKey = getMainQueueKey(serviceType, tenantId);
} else if (!queueRoutingInfo.getTenantId().equals(getIsolatedOrSystemTenantId(serviceType, tenantId))) {
log.debug("Tenant profile was changed but CheckPoint rule node still uses the queue from system level. [{}][{}]", tenantId, entityId);
queueKey = getMainQueueKey(serviceType, tenantId);
} else {
queueKey = new QueueKey(serviceType, queueRoutingInfo);
}
}
return resolve(queueKey, entityId);
}
private QueueKey getMainQueueKey(ServiceType serviceType, TenantId tenantId) {
return new QueueKey(serviceType, getIsolatedOrSystemTenantId(serviceType, tenantId));
}
private TopicPartitionInfo resolve(QueueKey queueKey, EntityId entityId) { private TopicPartitionInfo resolve(QueueKey queueKey, EntityId entityId) {
int hash = hashFunction.newHasher() int hash = hashFunction.newHasher()
.putLong(entityId.getId().getMostSignificantBits()) .putLong(entityId.getId().getMostSignificantBits())
@ -399,8 +365,6 @@ public class HashPartitionService implements PartitionService {
throw new RuntimeException("Tenant not found!"); throw new RuntimeException("Tenant not found!");
} }
switch (serviceType) { switch (serviceType) {
case TB_CORE:
return routingInfo.isIsolatedTbCore();
case TB_RULE_ENGINE: case TB_RULE_ENGINE:
return routingInfo.isIsolatedTbRuleEngine(); return routingInfo.isIsolatedTbRuleEngine();
default: default:

5
common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java

@ -32,13 +32,10 @@ import java.util.UUID;
*/ */
public interface PartitionService { public interface PartitionService {
@Deprecated TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId);
TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId, String queueName);
TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId); TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId);
TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId);
/** /**
* Received from the Discovery service when network topology is changed. * Received from the Discovery service when network topology is changed.
* @param currentService - current service information {@link org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo} * @param currentService - current service information {@link org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo}

1
common/queue/src/main/java/org/thingsboard/server/queue/discovery/TenantRoutingInfo.java

@ -21,6 +21,5 @@ import org.thingsboard.server.common.data.id.TenantId;
@Data @Data
public class TenantRoutingInfo { public class TenantRoutingInfo {
private final TenantId tenantId; private final TenantId tenantId;
private final boolean isolatedTbCore;
private final boolean isolatedTbRuleEngine; private final boolean isolatedTbRuleEngine;
} }

10
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -1088,7 +1088,7 @@ public class DefaultTransportService implements TransportService {
} }
private void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) { private void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) {
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueId(), tenantId, tbMsg.getOriginator()); TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, tbMsg.getOriginator());
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
log.trace("[{}][{}] Pushing to topic {} message {}", tenantId, tbMsg.getOriginator(), tpi.getFullTopicName(), tbMsg); log.trace("[{}][{}] Pushing to topic {} message {}", tenantId, tbMsg.getOriginator(), tpi.getFullTopicName(), tbMsg);
} }
@ -1105,18 +1105,18 @@ public class DefaultTransportService implements TransportService {
DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
RuleChainId ruleChainId; RuleChainId ruleChainId;
QueueId queueId; String queueName;
if (deviceProfile == null) { if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", deviceProfileId); log.warn("[{}] Device profile is null!", deviceProfileId);
ruleChainId = null; ruleChainId = null;
queueId = null; queueName = null;
} else { } else {
ruleChainId = deviceProfile.getDefaultRuleChainId(); ruleChainId = deviceProfile.getDefaultRuleChainId();
queueId = deviceProfile.getDefaultQueueId(); queueName = deviceProfile.getDefaultQueueName();
} }
TbMsg tbMsg = TbMsg.newMsg(queueId, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null); TbMsg tbMsg = TbMsg.newMsg(queueName, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null);
sendToRuleEngine(tenantId, tbMsg, callback); sendToRuleEngine(tenantId, tbMsg, callback);
} }

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportTenantRoutingInfoService.java

@ -38,7 +38,7 @@ public class TransportTenantRoutingInfoService implements TenantRoutingInfoServi
@Override @Override
public TenantRoutingInfo getRoutingInfo(TenantId tenantId) { public TenantRoutingInfo getRoutingInfo(TenantId tenantId) {
TenantProfile profile = tenantProfileCache.get(tenantId); TenantProfile profile = tenantProfileCache.get(tenantId);
return new TenantRoutingInfo(tenantId, profile.isIsolatedTbCore(), profile.isIsolatedTbRuleEngine()); return new TenantRoutingInfo(tenantId, profile.isIsolatedTbRuleEngine());
} }
} }

3
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java

@ -526,7 +526,8 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
.setRequestIdLSB(ctx.getRequestId().getLeastSignificantBits()); .setRequestIdLSB(ctx.getRequestId().getLeastSignificantBits());
if (e.isPresent()) { if (e.isPresent()) {
log.debug("[{}][{}] Failed to process task", ctx.getTenantId(), ctx.getRequestId(), e.get()); log.debug("[{}][{}] Failed to process task", ctx.getTenantId(), ctx.getRequestId(), e.get());
builder.setError(e.get().getMessage()); var message = e.get().getMessage();
builder.setError(message != null ? message : e.get().getClass().getSimpleName());
} else { } else {
if (enrichFunction != null) { if (enrichFunction != null) {
builder = enrichFunction.apply(builder); builder = enrichFunction.apply(builder);

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

@ -120,12 +120,6 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
DeviceProfile oldDeviceProfile = deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId); DeviceProfile oldDeviceProfile = deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId);
DeviceProfile savedDeviceProfile; DeviceProfile savedDeviceProfile;
try { try {
if (deviceProfile.getDefaultQueueId() == null && StringUtils.isNotEmpty(deviceProfile.getDefaultQueueName())) {
Queue existing = queueService.findQueueByTenantIdAndName(deviceProfile.getTenantId(), deviceProfile.getDefaultQueueName());
if (existing != null) {
deviceProfile.setDefaultQueueId(existing.getId());
}
}
savedDeviceProfile = deviceProfileDao.saveAndFlush(deviceProfile.getTenantId(), deviceProfile); savedDeviceProfile = deviceProfileDao.saveAndFlush(deviceProfile.getTenantId(), deviceProfile);
publishEvictEvent(new DeviceProfileEvictEvent(savedDeviceProfile.getTenantId(), savedDeviceProfile.getName(), publishEvictEvent(new DeviceProfileEvictEvent(savedDeviceProfile.getTenantId(), savedDeviceProfile.getName(),
oldDeviceProfile != null ? oldDeviceProfile.getName() : null, savedDeviceProfile.getId(), savedDeviceProfile.isDefault())); oldDeviceProfile != null ? oldDeviceProfile.getName() : null, savedDeviceProfile.getId(), savedDeviceProfile.isDefault()));

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

@ -181,6 +181,7 @@ public class ModelConstants {
public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id"; public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id";
public static final String DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY = "default_dashboard_id"; public static final String DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY = "default_dashboard_id";
public static final String DEVICE_PROFILE_DEFAULT_QUEUE_ID_PROPERTY = "default_queue_id"; public static final String DEVICE_PROFILE_DEFAULT_QUEUE_ID_PROPERTY = "default_queue_id";
public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name";
public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key"; public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key";
public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id"; public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id";
public static final String DEVICE_PROFILE_SOFTWARE_ID_PROPERTY = "software_id"; public static final String DEVICE_PROFILE_SOFTWARE_ID_PROPERTY = "software_id";

13
dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java

@ -88,8 +88,8 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
@Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY) @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY)
private UUID defaultDashboardId; private UUID defaultDashboardId;
@Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_QUEUE_ID_PROPERTY) @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY)
private UUID defaultQueueId; private String defaultQueueName;
@Type(type = "jsonb") @Type(type = "jsonb")
@Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb")
@ -133,9 +133,7 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
if (deviceProfile.getDefaultDashboardId() != null) { if (deviceProfile.getDefaultDashboardId() != null) {
this.defaultDashboardId = deviceProfile.getDefaultDashboardId().getId(); this.defaultDashboardId = deviceProfile.getDefaultDashboardId().getId();
} }
if (deviceProfile.getDefaultQueueId() != null) { this.defaultQueueName = deviceProfile.getDefaultQueueName();
this.defaultQueueId = deviceProfile.getDefaultQueueId().getId();
}
this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
if (deviceProfile.getFirmwareId() != null) { if (deviceProfile.getFirmwareId() != null) {
this.firmwareId = deviceProfile.getFirmwareId().getId(); this.firmwareId = deviceProfile.getFirmwareId().getId();
@ -176,6 +174,7 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
deviceProfile.setProvisionType(provisionType); deviceProfile.setProvisionType(provisionType);
deviceProfile.setDescription(description); deviceProfile.setDescription(description);
deviceProfile.setDefault(isDefault); deviceProfile.setDefault(isDefault);
deviceProfile.setDefaultQueueName(defaultQueueName);
deviceProfile.setProfileData(JacksonUtil.convertValue(profileData, DeviceProfileData.class)); deviceProfile.setProfileData(JacksonUtil.convertValue(profileData, DeviceProfileData.class));
if (defaultRuleChainId != null) { if (defaultRuleChainId != null) {
deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId)); deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId));
@ -183,15 +182,11 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
if (defaultDashboardId != null) { if (defaultDashboardId != null) {
deviceProfile.setDefaultDashboardId(new DashboardId(defaultDashboardId)); deviceProfile.setDefaultDashboardId(new DashboardId(defaultDashboardId));
} }
if (defaultQueueId != null) {
deviceProfile.setDefaultQueueId(new QueueId(defaultQueueId));
}
deviceProfile.setProvisionDeviceKey(provisionDeviceKey); deviceProfile.setProvisionDeviceKey(provisionDeviceKey);
if (firmwareId != null) { if (firmwareId != null) {
deviceProfile.setFirmwareId(new OtaPackageId(firmwareId)); deviceProfile.setFirmwareId(new OtaPackageId(firmwareId));
} }
if (softwareId != null) { if (softwareId != null) {
deviceProfile.setSoftwareId(new OtaPackageId(softwareId)); deviceProfile.setSoftwareId(new OtaPackageId(softwareId));
} }

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

@ -53,9 +53,6 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
@Column(name = ModelConstants.TENANT_PROFILE_IS_DEFAULT_PROPERTY) @Column(name = ModelConstants.TENANT_PROFILE_IS_DEFAULT_PROPERTY)
private boolean isDefault; private boolean isDefault;
@Column(name = ModelConstants.TENANT_PROFILE_ISOLATED_TB_CORE)
private boolean isolatedTbCore;
@Column(name = ModelConstants.TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE) @Column(name = ModelConstants.TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE)
private boolean isolatedTbRuleEngine; private boolean isolatedTbRuleEngine;
@ -75,7 +72,6 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
this.name = tenantProfile.getName(); this.name = tenantProfile.getName();
this.description = tenantProfile.getDescription(); this.description = tenantProfile.getDescription();
this.isDefault = tenantProfile.isDefault(); this.isDefault = tenantProfile.isDefault();
this.isolatedTbCore = tenantProfile.isIsolatedTbCore();
this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine(); this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine();
this.profileData = JacksonUtil.convertValue(tenantProfile.getProfileData(), ObjectNode.class); this.profileData = JacksonUtil.convertValue(tenantProfile.getProfileData(), ObjectNode.class);
} }
@ -101,7 +97,6 @@ public final class TenantProfileEntity extends BaseSqlEntity<TenantProfile> impl
tenantProfile.setName(name); tenantProfile.setName(name);
tenantProfile.setDescription(description); tenantProfile.setDescription(description);
tenantProfile.setDefault(isDefault); tenantProfile.setDefault(isDefault);
tenantProfile.setIsolatedTbCore(isolatedTbCore);
tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine); tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine);
tenantProfile.setProfileData(JacksonUtil.convertValue(profileData, TenantProfileData.class)); tenantProfile.setProfileData(JacksonUtil.convertValue(profileData, TenantProfileData.class));
return tenantProfile; return tenantProfile;

15
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -84,7 +84,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
private static final int DEFAULT_PAGE_SIZE = 1000; private static final int DEFAULT_PAGE_SIZE = 1000;
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
public static final String TB_RULE_CHAIN_INPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainInputNode";
@Autowired @Autowired
private RuleChainDao ruleChainDao; private RuleChainDao ruleChainDao;
@ -566,6 +566,19 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
} }
} }
} }
if (!CollectionUtils.isEmpty(metaData.getNodes())) {
metaData.getNodes().stream()
.filter(ruleNode -> ruleNode.getType().equals(TB_RULE_CHAIN_INPUT_NODE))
.forEach(ruleNode -> {
ObjectNode configuration = (ObjectNode) ruleNode.getConfiguration();
if (configuration.has("ruleChainId")) {
if (configuration.get("ruleChainId").asText().equals(oldRuleChainId.toString())) {
configuration.put("ruleChainId", newRuleChainId.toString());
ruleNode.setConfiguration(configuration);
}
}
});
}
} }
} }

9
dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java

@ -126,16 +126,11 @@ public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator<D
throw new DataValidationException("Another default device profile is present in scope of current tenant!"); throw new DataValidationException("Another default device profile is present in scope of current tenant!");
} }
} }
if (deviceProfile.getDefaultQueueId() != null) { if (StringUtils.isNotEmpty(deviceProfile.getDefaultQueueName())) {
Queue queue = queueService.findQueueById(tenantId, deviceProfile.getDefaultQueueId()); Queue queue = queueService.findQueueByTenantIdAndName(tenantId, deviceProfile.getDefaultQueueName());
if (queue == null) { if (queue == null) {
throw new DataValidationException("Device profile is referencing to non-existent queue!"); throw new DataValidationException("Device profile is referencing to non-existent queue!");
} }
TenantProfile tenantProfile = tenantProfileCache.get(deviceProfile.getTenantId());
if ((tenantProfile.isIsolatedTbRuleEngine() && !queue.getTenantId().equals(deviceProfile.getTenantId()))
|| (!tenantProfile.isIsolatedTbRuleEngine() && !queue.getTenantId().isNullUid())) {
throw new DataValidationException("Can't assign queue from different tenant!");
}
} }
if (deviceProfile.getProvisionType() == null) { if (deviceProfile.getProvisionType() == null) {
deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED); deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED);

2
dao/src/main/java/org/thingsboard/server/dao/service/validator/TenantProfileDataValidator.java

@ -100,8 +100,6 @@ public class TenantProfileDataValidator extends DataValidator<TenantProfile> {
throw new DataValidationException("Can't update non existing tenant profile!"); throw new DataValidationException("Can't update non existing tenant profile!");
} else if (old.isIsolatedTbRuleEngine() != tenantProfile.isIsolatedTbRuleEngine()) { } else if (old.isIsolatedTbRuleEngine() != tenantProfile.isIsolatedTbRuleEngine()) {
throw new DataValidationException("Can't update isolatedTbRuleEngine property!"); throw new DataValidationException("Can't update isolatedTbRuleEngine property!");
} else if (old.isIsolatedTbCore() != tenantProfile.isIsolatedTbCore()) {
throw new DataValidationException("Can't update isolatedTbCore property!");
} }
return old; return old;
} }

1
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java

@ -153,7 +153,6 @@ public class TenantProfileServiceImpl extends AbstractCachedEntityService<Tenant
profileData.setConfiguration(new DefaultTenantProfileConfiguration()); profileData.setConfiguration(new DefaultTenantProfileConfiguration());
defaultTenantProfile.setProfileData(profileData); defaultTenantProfile.setProfileData(profileData);
defaultTenantProfile.setDescription("Default tenant profile"); defaultTenantProfile.setDescription("Default tenant profile");
defaultTenantProfile.setIsolatedTbCore(false);
defaultTenantProfile.setIsolatedTbRuleEngine(false); defaultTenantProfile.setIsolatedTbRuleEngine(false);
defaultTenantProfile = saveTenantProfile(tenantId, defaultTenantProfile); defaultTenantProfile = saveTenantProfile(tenantId, defaultTenantProfile);
} }

1
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -171,7 +171,6 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
} }
@Override @Override
@Transactional(timeout = 60 * 60)
public void deleteTenant(TenantId tenantId) { public void deleteTenant(TenantId tenantId) {
log.trace("Executing deleteTenant [{}]", tenantId); log.trace("Executing deleteTenant [{}]", tenantId);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);

2
dao/src/main/resources/sql/schema-entities-idx.sql

@ -71,3 +71,5 @@ CREATE INDEX IF NOT EXISTS idx_widgets_bundle_external_id ON widgets_bundle(tena
CREATE INDEX IF NOT EXISTS idx_rule_node_external_id ON rule_node(rule_chain_id, external_id); CREATE INDEX IF NOT EXISTS idx_rule_node_external_id ON rule_node(rule_chain_id, external_id);
CREATE INDEX IF NOT EXISTS idx_rule_node_type ON rule_node(type); CREATE INDEX IF NOT EXISTS idx_rule_node_type ON rule_node(type);
CREATE INDEX IF NOT EXISTS idx_api_usage_state_entity_id ON api_usage_state(entity_id);

3
dao/src/main/resources/sql/schema-entities.sql

@ -253,14 +253,13 @@ CREATE TABLE IF NOT EXISTS device_profile (
software_id uuid, software_id uuid,
default_rule_chain_id uuid, default_rule_chain_id uuid,
default_dashboard_id uuid, default_dashboard_id uuid,
default_queue_id uuid, default_queue_name varchar(255),
provision_device_key varchar, provision_device_key varchar,
external_id uuid, external_id uuid,
CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id), CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id),
CONSTRAINT fk_default_queue_device_profile FOREIGN KEY (default_queue_id) REFERENCES queue(id),
CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES ota_package(id), CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES ota_package(id),
CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id) CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id)
); );

1
dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java

@ -51,7 +51,6 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest {
tenantProfile.setDefault(false); tenantProfile.setDefault(false);
tenantProfile.setName("Isolated TB Rule Engine"); tenantProfile.setName("Isolated TB Rule Engine");
tenantProfile.setDescription("Isolated TB Rule Engine tenant profile"); tenantProfile.setDescription("Isolated TB Rule Engine tenant profile");
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(true); tenantProfile.setIsolatedTbRuleEngine(true);
TenantProfileQueueConfiguration mainQueueConfiguration = new TenantProfileQueueConfiguration(); TenantProfileQueueConfiguration mainQueueConfiguration = new TenantProfileQueueConfiguration();

10
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java

@ -85,7 +85,6 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest {
Assert.assertEquals(tenantProfile.getDescription(), savedTenantProfile.getDescription()); Assert.assertEquals(tenantProfile.getDescription(), savedTenantProfile.getDescription());
Assert.assertEquals(tenantProfile.getProfileData(), savedTenantProfile.getProfileData()); Assert.assertEquals(tenantProfile.getProfileData(), savedTenantProfile.getProfileData());
Assert.assertEquals(tenantProfile.isDefault(), savedTenantProfile.isDefault()); Assert.assertEquals(tenantProfile.isDefault(), savedTenantProfile.isDefault());
Assert.assertEquals(tenantProfile.isIsolatedTbCore(), savedTenantProfile.isIsolatedTbCore());
Assert.assertEquals(tenantProfile.isIsolatedTbRuleEngine(), savedTenantProfile.isIsolatedTbRuleEngine()); Assert.assertEquals(tenantProfile.isIsolatedTbRuleEngine(), savedTenantProfile.isIsolatedTbRuleEngine());
savedTenantProfile.setName("New tenant profile"); savedTenantProfile.setName("New tenant profile");
@ -177,14 +176,6 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile); tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
} }
@Test(expected = DataValidationException.class)
public void testSaveSameTenantProfileWithDifferentIsolatedTbCore() {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);
savedTenantProfile.setIsolatedTbCore(true);
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
}
@Test(expected = DataValidationException.class) @Test(expected = DataValidationException.class)
public void testDeleteTenantProfileWithExistingTenant() { public void testDeleteTenantProfileWithExistingTenant() {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
@ -298,7 +289,6 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest {
profileData.setConfiguration(new DefaultTenantProfileConfiguration()); profileData.setConfiguration(new DefaultTenantProfileConfiguration());
tenantProfile.setProfileData(profileData); tenantProfile.setProfileData(profileData);
tenantProfile.setDefault(false); tenantProfile.setDefault(false);
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(false); tenantProfile.setIsolatedTbRuleEngine(false);
return tenantProfile; return tenantProfile;
} }

1
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java

@ -309,7 +309,6 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest {
profileData.setConfiguration(new DefaultTenantProfileConfiguration()); profileData.setConfiguration(new DefaultTenantProfileConfiguration());
tenantProfile.setProfileData(profileData); tenantProfile.setProfileData(profileData);
tenantProfile.setDefault(false); tenantProfile.setDefault(false);
tenantProfile.setIsolatedTbCore(true);
tenantProfile.setIsolatedTbRuleEngine(true); tenantProfile.setIsolatedTbRuleEngine(true);
TenantProfile isolatedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); TenantProfile isolatedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile);

2
msa/vc-executor/src/main/java/org/thingsboard/server/vc/service/VersionControlTenantRoutingInfoService.java

@ -25,6 +25,6 @@ public class VersionControlTenantRoutingInfoService implements TenantRoutingInfo
@Override @Override
public TenantRoutingInfo getRoutingInfo(TenantId tenantId) { public TenantRoutingInfo getRoutingInfo(TenantId tenantId) {
//This dummy implementation is ok since Version Control service does not produce any rule engine messages. //This dummy implementation is ok since Version Control service does not produce any rule engine messages.
return new TenantRoutingInfo(tenantId, false, false); return new TenantRoutingInfo(tenantId, false);
} }
} }

13
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java

@ -142,15 +142,12 @@ public interface TbContext {
*/ */
void output(TbMsg msg, String relationType); void output(TbMsg msg, String relationType);
@Deprecated
void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure);
/** /**
* Puts new message to custom queue for processing * Puts new message to custom queue for processing
* *
* @param msg - message * @param msg - message
*/ */
void enqueue(TbMsg msg, QueueId queueId, Runnable onSuccess, Consumer<Throwable> onFailure); void enqueue(TbMsg msg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure);
void enqueueForTellFailure(TbMsg msg, String failureMessage); void enqueueForTellFailure(TbMsg msg, String failureMessage);
@ -162,15 +159,15 @@ public interface TbContext {
void enqueueForTellNext(TbMsg msg, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure); void enqueueForTellNext(TbMsg msg, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure);
void enqueueForTellNext(TbMsg msg, QueueId queueId, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure); void enqueueForTellNext(TbMsg msg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure);
void enqueueForTellNext(TbMsg msg, QueueId queueId, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure); void enqueueForTellNext(TbMsg msg, String queueName, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure);
void ack(TbMsg tbMsg); void ack(TbMsg tbMsg);
TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data); TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data);
TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data); TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data);
TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data); TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data);

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java

@ -138,7 +138,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
} }
private void transformAndTellNext(TbContext ctx, TbMsg msg, EntityView entityView) { private void transformAndTellNext(TbContext ctx, TbMsg msg, EntityView entityView) {
ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueId(), msg.getType(), entityView.getId(), msg.getCustomerId(), msg.getMetaData(), msg.getData()), SUCCESS); ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueName(), msg.getType(), entityView.getId(), msg.getCustomerId(), msg.getMetaData(), msg.getData()), SUCCESS);
} }
private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) { private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java

@ -77,7 +77,7 @@ public class TbMsgCountNode implements TbNode {
TbMsgMetaData metaData = new TbMsgMetaData(); TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay)); metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay));
TbMsg tbMsg = TbMsg.newMsg(msg.getQueueId(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson)); TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson));
ctx.enqueueForTellNext(tbMsg, SUCCESS); ctx.enqueueForTellNext(tbMsg, SUCCESS);
scheduleTickMsg(ctx, tbMsg); scheduleTickMsg(ctx, tbMsg);
} else { } else {

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java

@ -41,17 +41,17 @@ import java.util.UUID;
) )
public class TbCheckpointNode implements TbNode { public class TbCheckpointNode implements TbNode {
private QueueId queueId; private String queueName;
@Override @Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
TbCheckpointNodeConfiguration config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class); TbCheckpointNodeConfiguration config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class);
this.queueId = new QueueId(UUID.fromString(config.getQueueId())); this.queueName = config.getQueueName();
} }
@Override @Override
public void onMsg(TbContext ctx, TbMsg msg) { public void onMsg(TbContext ctx, TbMsg msg) {
ctx.enqueueForTellNext(msg, queueId, TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); ctx.enqueueForTellNext(msg, queueName, TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error));
} }
@Override @Override

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.id.QueueId;
@Data @Data
public class TbCheckpointNodeConfiguration implements NodeConfiguration<TbCheckpointNodeConfiguration> { public class TbCheckpointNodeConfiguration implements NodeConfiguration<TbCheckpointNodeConfiguration> {
private String queueId; private String queueName;
@Override @Override
public TbCheckpointNodeConfiguration defaultConfiguration() { public TbCheckpointNodeConfiguration defaultConfiguration() {

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java

@ -60,7 +60,7 @@ class AlarmState {
private volatile Alarm currentAlarm; private volatile Alarm currentAlarm;
private volatile boolean initialFetchDone; private volatile boolean initialFetchDone;
private volatile TbMsgMetaData lastMsgMetaData; private volatile TbMsgMetaData lastMsgMetaData;
private volatile QueueId lastMsgQueueId; private volatile String lastMsgQueueName;
private volatile DataSnapshot dataSnapshot; private volatile DataSnapshot dataSnapshot;
private final DynamicPredicateValueCtx dynamicPredicateValueCtx; private final DynamicPredicateValueCtx dynamicPredicateValueCtx;
@ -74,7 +74,7 @@ class AlarmState {
public boolean process(TbContext ctx, TbMsg msg, DataSnapshot data, SnapshotUpdate update) throws ExecutionException, InterruptedException { public boolean process(TbContext ctx, TbMsg msg, DataSnapshot data, SnapshotUpdate update) throws ExecutionException, InterruptedException {
initCurrentAlarm(ctx); initCurrentAlarm(ctx);
lastMsgMetaData = msg.getMetaData(); lastMsgMetaData = msg.getMetaData();
lastMsgQueueId = msg.getQueueId(); lastMsgQueueName = msg.getQueueName();
this.dataSnapshot = data; this.dataSnapshot = data;
try { try {
return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval); return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval);
@ -195,7 +195,7 @@ class AlarmState {
metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString()); metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString());
} }
setAlarmConditionMetadata(ruleState, metaData); setAlarmConditionMetadata(ruleState, metaData);
TbMsg newMsg = ctx.newMsg(lastMsgQueueId != null ? lastMsgQueueId : null, "ALARM", TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : null, "ALARM",
originator, msg != null ? msg.getCustomerId() : null, metaData, data); originator, msg != null ? msg.getCustomerId() : null, metaData, data);
ctx.enqueueForTellNext(newMsg, relationType); ctx.enqueueForTellNext(newMsg, relationType);
} }

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java

@ -116,10 +116,10 @@ public class TbSendRPCRequestNode implements TbNode {
ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> { ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> {
if (ruleEngineDeviceRpcResponse.getError().isEmpty()) { if (ruleEngineDeviceRpcResponse.getError().isEmpty()) {
TbMsg next = ctx.newMsg(msg.getQueueId(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}")); TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}"));
ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS); ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS);
} else { } else {
TbMsg next = ctx.newMsg(msg.getQueueId(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name())); TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name()));
ctx.enqueueForTellFailure(next, ruleEngineDeviceRpcResponse.getError().get().name()); ctx.enqueueForTellFailure(next, ruleEngineDeviceRpcResponse.getError().get().name());
} }
}); });

2
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

2
transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java

@ -20,12 +20,14 @@ import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.Arrays; import java.util.Arrays;
@SpringBootConfiguration @SpringBootConfiguration
@EnableAsync @EnableAsync
@EnableAutoConfiguration @EnableAutoConfiguration
@EnableScheduling
@ComponentScan({"org.thingsboard.server.mqtt", "org.thingsboard.server.common", "org.thingsboard.server.transport.mqtt", "org.thingsboard.server.queue", "org.thingsboard.server.cache"}) @ComponentScan({"org.thingsboard.server.mqtt", "org.thingsboard.server.common", "org.thingsboard.server.transport.mqtt", "org.thingsboard.server.queue", "org.thingsboard.server.cache"})
public class ThingsboardMqttTransportApplication { public class ThingsboardMqttTransportApplication {

4
ui-ngx/src/app/core/http/queue.service.ts

@ -35,6 +35,10 @@ export class QueueService {
return this.http.get<QueueInfo>(`/api/queues/${queueId}`, defaultHttpOptionsFromConfig(config)); return this.http.get<QueueInfo>(`/api/queues/${queueId}`, defaultHttpOptionsFromConfig(config));
} }
public getQueueByName(queueName: string, config?: RequestConfig): Observable<QueueInfo> {
return this.http.get<QueueInfo>(`/api/queues/name/${queueName}`, defaultHttpOptionsFromConfig(config));
}
public getTenantQueuesByServiceType(pageLink: PageLink, public getTenantQueuesByServiceType(pageLink: PageLink,
serviceType: ServiceType, serviceType: ServiceType,
config?: RequestConfig): Observable<PageData<QueueInfo>> { config?: RequestConfig): Observable<PageData<QueueInfo>> {

5
ui-ngx/src/app/core/services/dashboard-utils.service.ts

@ -30,7 +30,7 @@ import {
WidgetLayout WidgetLayout
} from '@shared/models/dashboard.models'; } from '@shared/models/dashboard.models';
import { isDefined, isString, isUndefined } from '@core/utils'; import { isDefined, isString, isUndefined } from '@core/utils';
import { Datasource, DatasourceType, Widget } from '@app/shared/models/widget.models'; import { Datasource, DatasourceType, Widget, widgetType } from '@app/shared/models/widget.models';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
import { AliasFilterType, EntityAlias, EntityAliasFilter } from '@app/shared/models/alias.models'; import { AliasFilterType, EntityAlias, EntityAliasFilter } from '@app/shared/models/alias.models';
import { EntityId } from '@app/shared/models/id/entity-id'; import { EntityId } from '@app/shared/models/id/entity-id';
@ -106,7 +106,8 @@ export class DashboardUtilsService {
const targetDevicesByAliasId: {[aliasId: string]: Array<Array<string>>} = {}; const targetDevicesByAliasId: {[aliasId: string]: Array<Array<string>>} = {};
for (const widgetId of Object.keys(dashboard.configuration.widgets)) { for (const widgetId of Object.keys(dashboard.configuration.widgets)) {
const widget = dashboard.configuration.widgets[widgetId]; const widget = dashboard.configuration.widgets[widgetId];
widget.config.datasources.forEach((datasource) => { const datasources = widget.type === widgetType.alarm ? [widget.config.alarmSource] : widget.config.datasources;
datasources.forEach((datasource) => {
if (datasource.entityAliasId) { if (datasource.entityAliasId) {
const aliasId = datasource.entityAliasId; const aliasId = datasource.entityAliasId;
let aliasDatasources = datasourcesByAliasId[aliasId]; let aliasDatasources = datasourcesByAliasId[aliasId];

34
ui-ngx/src/app/core/services/item-buffer.service.ts

@ -17,7 +17,14 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Dashboard, DashboardLayoutId } from '@app/shared/models/dashboard.models'; import { Dashboard, DashboardLayoutId } from '@app/shared/models/dashboard.models';
import { AliasesInfo, EntityAlias, EntityAliases, EntityAliasInfo } from '@shared/models/alias.models'; import { AliasesInfo, EntityAlias, EntityAliases, EntityAliasInfo } from '@shared/models/alias.models';
import { DatasourceType, Widget, WidgetPosition, WidgetSize } from '@shared/models/widget.models'; import {
Datasource,
DatasourceType,
Widget,
WidgetPosition,
WidgetSize,
widgetType
} from '@shared/models/widget.models';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { deepClone, isEqual } from '@core/utils'; import { deepClone, isEqual } from '@core/utils';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
@ -87,12 +94,13 @@ export class ItemBufferService {
}; };
const originalColumns = this.getOriginalColumns(dashboard, sourceState, sourceLayout); const originalColumns = this.getOriginalColumns(dashboard, sourceState, sourceLayout);
const originalSize = this.getOriginalSize(dashboard, sourceState, sourceLayout, widget); const originalSize = this.getOriginalSize(dashboard, sourceState, sourceLayout, widget);
const datasources: Datasource[] = widget.type === widgetType.alarm ? [widget.config.alarmSource] : widget.config.datasources;
if (widget.config && dashboard.configuration if (widget.config && dashboard.configuration
&& dashboard.configuration.entityAliases) { && dashboard.configuration.entityAliases) {
let entityAlias: EntityAlias; let entityAlias: EntityAlias;
if (widget.config.datasources) { if (datasources) {
for (let i = 0; i < widget.config.datasources.length; i++) { for (let i = 0; i < datasources.length; i++) {
const datasource = widget.config.datasources[i]; const datasource = datasources[i];
if ((datasource.type === DatasourceType.entity || datasource.type === DatasourceType.entityCount) && datasource.entityAliasId) { if ((datasource.type === DatasourceType.entity || datasource.type === DatasourceType.entityCount) && datasource.entityAliasId) {
entityAlias = dashboard.configuration.entityAliases[datasource.entityAliasId]; entityAlias = dashboard.configuration.entityAliases[datasource.entityAliasId];
if (entityAlias) { if (entityAlias) {
@ -116,9 +124,9 @@ export class ItemBufferService {
if (widget.config && dashboard.configuration if (widget.config && dashboard.configuration
&& dashboard.configuration.filters) { && dashboard.configuration.filters) {
let filter: Filter; let filter: Filter;
if (widget.config.datasources) { if (datasources) {
for (let i = 0; i < widget.config.datasources.length; i++) { for (let i = 0; i < datasources.length; i++) {
const datasource = widget.config.datasources[i]; const datasource = datasources[i];
if ((datasource.type === DatasourceType.entity || datasource.type === DatasourceType.entityCount) && datasource.filterId) { if ((datasource.type === DatasourceType.entity || datasource.type === DatasourceType.entityCount) && datasource.filterId) {
filter = dashboard.configuration.filters[datasource.filterId]; filter = dashboard.configuration.filters[datasource.filterId];
if (filter) { if (filter) {
@ -438,7 +446,11 @@ export class ItemBufferService {
const datasourceIndex = Number(datasourceIndexStr); const datasourceIndex = Number(datasourceIndexStr);
aliasInfo = aliasesInfo.datasourceAliases[datasourceIndex]; aliasInfo = aliasesInfo.datasourceAliases[datasourceIndex];
newAliasId = this.getEntityAliasId(entityAliases, aliasInfo); newAliasId = this.getEntityAliasId(entityAliases, aliasInfo);
widget.config.datasources[datasourceIndex].entityAliasId = newAliasId; if (widget.type === widgetType.alarm) {
widget.config.alarmSource.entityAliasId = newAliasId;
} else {
widget.config.datasources[datasourceIndex].entityAliasId = newAliasId;
}
} }
for (const targetDeviceAliasIndexStr of Object.keys(aliasesInfo.targetDeviceAliases)) { for (const targetDeviceAliasIndexStr of Object.keys(aliasesInfo.targetDeviceAliases)) {
const targetDeviceAliasIndex = Number(targetDeviceAliasIndexStr); const targetDeviceAliasIndex = Number(targetDeviceAliasIndexStr);
@ -457,7 +469,11 @@ export class ItemBufferService {
const datasourceIndex = Number(datasourceIndexStr); const datasourceIndex = Number(datasourceIndexStr);
filterInfo = filtersInfo.datasourceFilters[datasourceIndex]; filterInfo = filtersInfo.datasourceFilters[datasourceIndex];
newFilterId = this.getFilterId(filters, filterInfo); newFilterId = this.getFilterId(filters, filterInfo);
widget.config.datasources[datasourceIndex].filterId = newFilterId; if (widget.type === widgetType.alarm) {
widget.config.alarmSource.filterId = newFilterId;
} else {
widget.config.datasources[datasourceIndex].filterId = newFilterId;
}
} }
return filters; return filters;
} }

1
ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts

@ -631,7 +631,6 @@ export class ImportExportService {
private validateImportedTenantProfile(tenantProfile: TenantProfile): boolean { private validateImportedTenantProfile(tenantProfile: TenantProfile): boolean {
return isDefined(tenantProfile.name) return isDefined(tenantProfile.name)
&& isDefined(tenantProfile.profileData) && isDefined(tenantProfile.profileData)
&& isDefined(tenantProfile.isolatedTbCore)
&& isDefined(tenantProfile.isolatedTbRuleEngine); && isDefined(tenantProfile.isolatedTbRuleEngine);
} }

2
ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html

@ -56,7 +56,7 @@
</tb-dashboard-autocomplete> </tb-dashboard-autocomplete>
<tb-queue-autocomplete <tb-queue-autocomplete
[queueType]="serviceType" [queueType]="serviceType"
formControlName="defaultQueueId"> formControlName="defaultQueueName">
</tb-queue-autocomplete> </tb-queue-autocomplete>
<mat-form-field fxHide class="mat-block"> <mat-form-field fxHide class="mat-block">
<mat-label translate>device-profile.type</mat-label> <mat-label translate>device-profile.type</mat-label>

7
ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts

@ -50,7 +50,6 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper';
import { deepTrim } from '@core/utils'; import { deepTrim } from '@core/utils';
import { ServiceType } from '@shared/models/queue.models'; import { ServiceType } from '@shared/models/queue.models';
import { DashboardId } from '@shared/models/id/dashboard-id'; import { DashboardId } from '@shared/models/id/dashboard-id';
import { QueueId } from '@shared/models/id/queue-id';
export interface AddDeviceProfileDialogData { export interface AddDeviceProfileDialogData {
deviceProfileName: string; deviceProfileName: string;
@ -111,7 +110,7 @@ export class AddDeviceProfileDialogComponent extends
image: [null, []], image: [null, []],
defaultRuleChainId: [null, []], defaultRuleChainId: [null, []],
defaultDashboardId: [null, []], defaultDashboardId: [null, []],
defaultQueueId: [null, []], defaultQueueName: [null, []],
description: ['', []] description: ['', []]
} }
); );
@ -188,6 +187,7 @@ export class AddDeviceProfileDialogComponent extends
name: this.deviceProfileDetailsFormGroup.get('name').value, name: this.deviceProfileDetailsFormGroup.get('name').value,
type: this.deviceProfileDetailsFormGroup.get('type').value, type: this.deviceProfileDetailsFormGroup.get('type').value,
image: this.deviceProfileDetailsFormGroup.get('image').value, image: this.deviceProfileDetailsFormGroup.get('image').value,
defaultQueueName: this.deviceProfileDetailsFormGroup.get('defaultQueueName').value,
transportType: this.transportConfigFormGroup.get('transportType').value, transportType: this.transportConfigFormGroup.get('transportType').value,
provisionType: deviceProvisionConfiguration.type, provisionType: deviceProvisionConfiguration.type,
provisionDeviceKey, provisionDeviceKey,
@ -205,9 +205,6 @@ export class AddDeviceProfileDialogComponent extends
if (this.deviceProfileDetailsFormGroup.get('defaultDashboardId').value) { if (this.deviceProfileDetailsFormGroup.get('defaultDashboardId').value) {
deviceProfile.defaultDashboardId = new DashboardId(this.deviceProfileDetailsFormGroup.get('defaultDashboardId').value); deviceProfile.defaultDashboardId = new DashboardId(this.deviceProfileDetailsFormGroup.get('defaultDashboardId').value);
} }
if (this.deviceProfileDetailsFormGroup.get('defaultQueueId').value) {
deviceProfile.defaultQueueId = new QueueId(this.deviceProfileDetailsFormGroup.get('defaultQueueId').value);
}
this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).subscribe( this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).subscribe(
(savedDeviceProfile) => { (savedDeviceProfile) => {
this.dialogRef.close(savedDeviceProfile); this.dialogRef.close(savedDeviceProfile);

2
ui-ngx/src/app/modules/home/components/profile/device-profile.component.html

@ -75,7 +75,7 @@
</tb-dashboard-autocomplete> </tb-dashboard-autocomplete>
<tb-queue-autocomplete <tb-queue-autocomplete
[queueType]="serviceType" [queueType]="serviceType"
formControlName="defaultQueueId"> formControlName="defaultQueueName">
</tb-queue-autocomplete> </tb-queue-autocomplete>
<tb-ota-package-autocomplete <tb-ota-package-autocomplete
[useFullEntityId]="true" [useFullEntityId]="true"

8
ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts

@ -42,7 +42,6 @@ import { ServiceType } from '@shared/models/queue.models';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { OtaUpdateType } from '@shared/models/ota-package.models'; import { OtaUpdateType } from '@shared/models/ota-package.models';
import { DashboardId } from '@shared/models/id/dashboard-id'; import { DashboardId } from '@shared/models/id/dashboard-id';
import { QueueId } from '@shared/models/id/queue-id';
@Component({ @Component({
selector: 'tb-device-profile', selector: 'tb-device-profile',
@ -118,7 +117,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
}), }),
defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []],
defaultDashboardId: [entity && entity.defaultDashboardId ? entity.defaultDashboardId.id : null, []], defaultDashboardId: [entity && entity.defaultDashboardId ? entity.defaultDashboardId.id : null, []],
defaultQueueId: [entity && entity.defaultQueueId ? entity.defaultQueueId.id : null, []], defaultQueueName: [entity ? entity.defaultQueueName : null, []],
firmwareId: [entity ? entity.firmwareId : null], firmwareId: [entity ? entity.firmwareId : null],
softwareId: [entity ? entity.softwareId : null], softwareId: [entity ? entity.softwareId : null],
description: [entity ? entity.description : '', []], description: [entity ? entity.description : '', []],
@ -198,7 +197,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
}}, {emitEvent: false}); }}, {emitEvent: false});
this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false}); this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false});
this.entityForm.patchValue({defaultDashboardId: entity.defaultDashboardId ? entity.defaultDashboardId.id : null}, {emitEvent: false}); this.entityForm.patchValue({defaultDashboardId: entity.defaultDashboardId ? entity.defaultDashboardId.id : null}, {emitEvent: false});
this.entityForm.patchValue({defaultQueueId: entity.defaultQueueId ? entity.defaultQueueId.id : null}, {emitEvent: false}); this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false});
this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false});
this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false}); this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false});
this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); this.entityForm.patchValue({description: entity.description}, {emitEvent: false});
@ -211,9 +210,6 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
if (formValue.defaultDashboardId) { if (formValue.defaultDashboardId) {
formValue.defaultDashboardId = new DashboardId(formValue.defaultDashboardId); formValue.defaultDashboardId = new DashboardId(formValue.defaultDashboardId);
} }
if (formValue.defaultQueueId) {
formValue.defaultQueueId = new QueueId(formValue.defaultQueueId);
}
const deviceProvisionConfiguration: DeviceProvisionConfiguration = formValue.profileData.provisionConfiguration; const deviceProvisionConfiguration: DeviceProvisionConfiguration = formValue.profileData.provisionConfiguration;
formValue.provisionType = deviceProvisionConfiguration.type; formValue.provisionType = deviceProvisionConfiguration.type;
formValue.provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey; formValue.provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey;

4
ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html

@ -59,10 +59,6 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<div fxLayout="column"> <div fxLayout="column">
<mat-checkbox class="hinted-checkbox" formControlName="isolatedTbCore">
<div>{{ 'tenant.isolated-tb-core' | translate }}</div>
<div class="tb-hint">{{'tenant.isolated-tb-core-details' | translate}}</div>
</mat-checkbox>
<mat-checkbox class="hinted-checkbox" formControlName="isolatedTbRuleEngine"> <mat-checkbox class="hinted-checkbox" formControlName="isolatedTbRuleEngine">
<div>{{ 'tenant.isolated-tb-rule-engine' | translate }}</div> <div>{{ 'tenant.isolated-tb-rule-engine' | translate }}</div>
<div class="tb-hint">{{'tenant.isolated-tb-rule-engine-details' | translate}}</div> <div class="tb-hint">{{'tenant.isolated-tb-rule-engine-details' | translate}}</div>

3
ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts

@ -81,7 +81,6 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
const formGroup = this.fb.group( const formGroup = this.fb.group(
{ {
name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
isolatedTbCore: [entity ? entity.isolatedTbCore : false, []],
isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []],
profileData: this.fb.group({ profileData: this.fb.group({
configuration: [entity && !this.isAdd ? entity?.profileData.configuration configuration: [entity && !this.isAdd ? entity?.profileData.configuration
@ -107,7 +106,6 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
updateForm(entity: TenantProfile) { updateForm(entity: TenantProfile) {
this.entityForm.patchValue({name: entity.name}, {emitEvent: false}); this.entityForm.patchValue({name: entity.name}, {emitEvent: false});
this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore}, {emitEvent: false});
this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}, {emitEvent: false}); this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}, {emitEvent: false});
this.entityForm.get('profileData').patchValue({ this.entityForm.get('profileData').patchValue({
configuration: !this.isAdd ? entity.profileData?.configuration : createTenantProfileConfiguration(TenantProfileType.DEFAULT) configuration: !this.isAdd ? entity.profileData?.configuration : createTenantProfileConfiguration(TenantProfileType.DEFAULT)
@ -121,7 +119,6 @@ export class TenantProfileComponent extends EntityComponent<TenantProfile> {
if (this.isEditValue) { if (this.isEditValue) {
this.entityForm.enable({emitEvent: false}); this.entityForm.enable({emitEvent: false});
if (!this.isAdd) { if (!this.isAdd) {
this.entityForm.get('isolatedTbCore').disable({emitEvent: false});
this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false}); this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false});
} }
} else { } else {

3
ui-ngx/src/app/modules/home/components/widget/widget-container.component.html

@ -25,7 +25,8 @@
'tb-highlighted': isHighlighted(widget), 'tb-highlighted': isHighlighted(widget),
'tb-not-highlighted': isNotHighlighted(widget), 'tb-not-highlighted': isNotHighlighted(widget),
'mat-elevation-z4': widget.dropShadow, 'mat-elevation-z4': widget.dropShadow,
'tb-has-timewindow': widget.hasTimewindow 'tb-has-timewindow': widget.hasTimewindow,
'tb-edit': isEdit
}" }"
[ngStyle]="widget.style" [ngStyle]="widget.style"
(mousedown)="onMouseDown($event)" (mousedown)="onMouseDown($event)"

4
ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss

@ -114,4 +114,8 @@ div.tb-widget {
&.tb-not-highlighted { &.tb-not-highlighted {
opacity: .5; opacity: .5;
} }
&.tb-edit {
cursor: pointer;
}
} }

2
ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html

@ -95,7 +95,7 @@
<tb-queue-autocomplete <tb-queue-autocomplete
[ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 1}" [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 1}"
[queueType]="serviceType" [queueType]="serviceType"
formControlName="defaultQueueId"> formControlName="defaultQueueName">
</tb-queue-autocomplete> </tb-queue-autocomplete>
</div> </div>
</div> </div>

11
ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts

@ -49,7 +49,6 @@ import { MediaBreakpoints } from '@shared/models/constants';
import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { RuleChainId } from '@shared/models/id/rule-chain-id';
import { ServiceType } from '@shared/models/queue.models'; import { ServiceType } from '@shared/models/queue.models';
import { deepTrim } from '@core/utils'; import { deepTrim } from '@core/utils';
import { QueueId } from '@shared/models/id/queue-id';
@Component({ @Component({
selector: 'tb-device-wizard', selector: 'tb-device-wizard',
@ -114,7 +113,7 @@ export class DeviceWizardDialogComponent extends
deviceProfileId: [null, Validators.required], deviceProfileId: [null, Validators.required],
newDeviceProfileTitle: [{value: null, disabled: true}], newDeviceProfileTitle: [{value: null, disabled: true}],
defaultRuleChainId: [{value: null, disabled: true}], defaultRuleChainId: [{value: null, disabled: true}],
defaultQueueId: [{value: null, disabled: true}], defaultQueueName: [{value: null, disabled: true}],
description: [''] description: ['']
} }
); );
@ -127,7 +126,7 @@ export class DeviceWizardDialogComponent extends
this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null); this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null);
this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable(); this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable();
this.deviceWizardFormGroup.get('defaultRuleChainId').disable(); this.deviceWizardFormGroup.get('defaultRuleChainId').disable();
this.deviceWizardFormGroup.get('defaultQueueId').disable(); this.deviceWizardFormGroup.get('defaultQueueName').disable();
this.deviceWizardFormGroup.updateValueAndValidity(); this.deviceWizardFormGroup.updateValueAndValidity();
this.createProfile = false; this.createProfile = false;
} else { } else {
@ -136,7 +135,7 @@ export class DeviceWizardDialogComponent extends
this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]); this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]);
this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable(); this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable();
this.deviceWizardFormGroup.get('defaultRuleChainId').enable(); this.deviceWizardFormGroup.get('defaultRuleChainId').enable();
this.deviceWizardFormGroup.get('defaultQueueId').enable(); this.deviceWizardFormGroup.get('defaultQueueName').enable();
this.deviceWizardFormGroup.updateValueAndValidity(); this.deviceWizardFormGroup.updateValueAndValidity();
this.createProfile = true; this.createProfile = true;
@ -298,6 +297,7 @@ export class DeviceWizardDialogComponent extends
const deviceProfile: DeviceProfile = { const deviceProfile: DeviceProfile = {
name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value, name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value,
type: DeviceProfileType.DEFAULT, type: DeviceProfileType.DEFAULT,
defaultQueueName: this.deviceWizardFormGroup.get('defaultQueueName').value,
transportType: this.transportConfigFormGroup.get('transportType').value, transportType: this.transportConfigFormGroup.get('transportType').value,
provisionType: deviceProvisionConfiguration.type, provisionType: deviceProvisionConfiguration.type,
provisionDeviceKey, provisionDeviceKey,
@ -311,9 +311,6 @@ export class DeviceWizardDialogComponent extends
if (this.deviceWizardFormGroup.get('defaultRuleChainId').value) { if (this.deviceWizardFormGroup.get('defaultRuleChainId').value) {
deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceWizardFormGroup.get('defaultRuleChainId').value); deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceWizardFormGroup.get('defaultRuleChainId').value);
} }
if (this.deviceWizardFormGroup.get('defaultQueueId').value) {
deviceProfile.defaultQueueId = new QueueId(this.deviceWizardFormGroup.get('defaultQueueId').value);
}
return this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).pipe( return this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).pipe(
tap((profile) => { tap((profile) => {
this.currentDeviceProfileTransportType = profile.transportType; this.currentDeviceProfileTransportType = profile.transportType;

2
ui-ngx/src/app/modules/home/models/dashboard-component.models.ts

@ -428,7 +428,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
this.hasAggregation = this.widget.type === widgetType.timeseries; this.hasAggregation = this.widget.type === widgetType.timeseries;
this.style = {cursor: 'pointer', this.style = {
color: this.color, color: this.color,
backgroundColor: this.backgroundColor, backgroundColor: this.backgroundColor,
padding: this.padding, padding: this.padding,

5
ui-ngx/src/app/shared/components/markdown.component.ts

@ -126,11 +126,11 @@ export class TbMarkdownComponent implements OnChanges {
this.handlePlugins(this.tbMarkdownInstanceComponentRef.location.nativeElement); this.handlePlugins(this.tbMarkdownInstanceComponentRef.location.nativeElement);
this.markdownService.highlight(this.tbMarkdownInstanceComponentRef.location.nativeElement); this.markdownService.highlight(this.tbMarkdownInstanceComponentRef.location.nativeElement);
readyObservable = this.handleImages(this.tbMarkdownInstanceComponentRef.location.nativeElement); readyObservable = this.handleImages(this.tbMarkdownInstanceComponentRef.location.nativeElement);
this.cd.detectChanges();
this.error = null; this.error = null;
} catch (error) { } catch (error) {
readyObservable = this.handleError(compiled, error); readyObservable = this.handleError(compiled, error);
} }
this.cd.detectChanges();
readyObservable.subscribe(() => { readyObservable.subscribe(() => {
this.ready.emit(); this.ready.emit();
}); });
@ -146,9 +146,8 @@ export class TbMarkdownComponent implements OnChanges {
private handleError(template: string, error): Observable<void> { private handleError(template: string, error): Observable<void> {
this.error = (error ? error + '' : 'Failed to render markdown!').replace(/\n/g, '<br>'); this.error = (error ? error + '' : 'Failed to render markdown!').replace(/\n/g, '<br>');
this.destroyMarkdownInstanceResources(); this.markdownContainer.clear();
if (this.fallbackToPlainMarkdownValue) { if (this.fallbackToPlainMarkdownValue) {
this.markdownContainer.clear();
const element = this.fallbackElement.nativeElement; const element = this.fallbackElement.nativeElement;
element.innerHTML = template; element.innerHTML = template;
this.handlePlugins(element); this.handlePlugins(element);

6
ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html

@ -18,11 +18,11 @@
<mat-form-field [formGroup]="selectQueueFormGroup" class="mat-block autocomplete-queue"> <mat-form-field [formGroup]="selectQueueFormGroup" class="mat-block autocomplete-queue">
<input matInput type="text" placeholder="{{ 'queue.queue-name' | translate }}" <input matInput type="text" placeholder="{{ 'queue.queue-name' | translate }}"
#queueInput #queueInput
formControlName="queueId" formControlName="queueName"
(focusin)="onFocus()" (focusin)="onFocus()"
[required]="required" [required]="required"
[matAutocomplete]="queueAutocomplete"> [matAutocomplete]="queueAutocomplete">
<button *ngIf="selectQueueFormGroup.get('queueId').value && !disabled" <button *ngIf="selectQueueFormGroup.get('queueName').value && !disabled"
type="button" type="button"
matSuffix mat-button mat-icon-button aria-label="Clear" matSuffix mat-button mat-icon-button aria-label="Clear"
(click)="clear()"> (click)="clear()">
@ -50,7 +50,7 @@
</div> </div>
</mat-option> </mat-option>
</mat-autocomplete> </mat-autocomplete>
<mat-error *ngIf="selectQueueFormGroup.get('queueId').hasError('required')"> <mat-error *ngIf="selectQueueFormGroup.get('queueName').hasError('required')">
{{ 'queue.queue-required' | translate }} {{ 'queue.queue-required' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>

33
ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts

@ -23,7 +23,6 @@ import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { EntityType } from '@shared/models/entity-type.models';
import { BaseData } from '@shared/models/base-data'; import { BaseData } from '@shared/models/base-data';
import { EntityService } from '@core/http/entity.service'; import { EntityService } from '@core/http/entity.service';
import { TruncatePipe } from '@shared/pipe/truncate.pipe'; import { TruncatePipe } from '@shared/pipe/truncate.pipe';
@ -87,7 +86,7 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
private queueService: QueueService, private queueService: QueueService,
private fb: FormBuilder) { private fb: FormBuilder) {
this.selectQueueFormGroup = this.fb.group({ this.selectQueueFormGroup = this.fb.group({
queueId: [null] queueName: [null]
}); });
} }
@ -99,7 +98,7 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
} }
ngOnInit() { ngOnInit() {
this.filteredQueues = this.selectQueueFormGroup.get('queueId').valueChanges this.filteredQueues = this.selectQueueFormGroup.get('queueName').valueChanges
.pipe( .pipe(
debounceTime(150), debounceTime(150),
tap(value => { tap(value => {
@ -107,7 +106,7 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
if (typeof value === 'string' || !value) { if (typeof value === 'string' || !value) {
modelValue = null; modelValue = null;
} else { } else {
modelValue = value.id.id; modelValue = value.name;
} }
this.updateView(modelValue); this.updateView(modelValue);
if (value === null) { if (value === null) {
@ -123,15 +122,6 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
ngAfterViewInit(): void {} ngAfterViewInit(): void {}
getCurrentEntity(): BaseData<EntityId> | null {
const currentRuleChain = this.selectQueueFormGroup.get('queueId').value;
if (currentRuleChain && typeof currentRuleChain !== 'string') {
return currentRuleChain as BaseData<EntityId>;
} else {
return null;
}
}
setDisabledState(isDisabled: boolean): void { setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled; this.disabled = isDisabled;
if (this.disabled) { if (this.disabled) {
@ -148,15 +138,14 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
writeValue(value: string | null): void { writeValue(value: string | null): void {
this.searchText = ''; this.searchText = '';
if (value != null) { if (value != null) {
const targetEntityType = EntityType.QUEUE; this.queueService.getQueueByName(value, {ignoreLoading: true, ignoreErrors: true}).subscribe(
this.entityService.getEntity(targetEntityType, value, {ignoreLoading: true, ignoreErrors: true}).subscribe(
(entity) => { (entity) => {
this.modelValue = entity.id.id; this.modelValue = entity.name;
this.selectQueueFormGroup.get('queueId').patchValue(entity, {emitEvent: false}); this.selectQueueFormGroup.get('queueName').patchValue(entity, {emitEvent: false});
}, },
() => { () => {
this.modelValue = null; this.modelValue = null;
this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: false}); this.selectQueueFormGroup.get('queueName').patchValue('', {emitEvent: false});
if (value !== null) { if (value !== null) {
this.propagateChange(this.modelValue); this.propagateChange(this.modelValue);
} }
@ -164,20 +153,20 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
); );
} else { } else {
this.modelValue = null; this.modelValue = null;
this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: false}); this.selectQueueFormGroup.get('queueName').patchValue('', {emitEvent: false});
} }
this.dirty = true; this.dirty = true;
} }
onFocus() { onFocus() {
if (this.dirty) { if (this.dirty) {
this.selectQueueFormGroup.get('queueId').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.selectQueueFormGroup.get('queueName').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false; this.dirty = false;
} }
} }
reset() { reset() {
this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: false}); this.selectQueueFormGroup.get('queueName').patchValue('', {emitEvent: false});
} }
updateView(value: string | null) { updateView(value: string | null) {
@ -214,7 +203,7 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit
} }
clear() { clear() {
this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: true}); this.selectQueueFormGroup.get('queueName').patchValue('', {emitEvent: true});
setTimeout(() => { setTimeout(() => {
this.queueInput.nativeElement.blur(); this.queueInput.nativeElement.blur();
this.queueInput.nativeElement.focus(); this.queueInput.nativeElement.focus();

3
ui-ngx/src/app/shared/models/device.models.ts

@ -29,7 +29,6 @@ import * as _moment from 'moment';
import { AbstractControl, ValidationErrors } from '@angular/forms'; import { AbstractControl, ValidationErrors } from '@angular/forms';
import { OtaPackageId } from '@shared/models/id/ota-package-id'; import { OtaPackageId } from '@shared/models/id/ota-package-id';
import { DashboardId } from '@shared/models/id/dashboard-id'; import { DashboardId } from '@shared/models/id/dashboard-id';
import { QueueId } from '@shared/models/id/queue-id';
import { DataType } from '@shared/models/constants'; import { DataType } from '@shared/models/constants';
import { import {
getDefaultProfileClientLwM2mSettingsConfig, getDefaultProfileClientLwM2mSettingsConfig,
@ -576,7 +575,7 @@ export interface DeviceProfile extends BaseData<DeviceProfileId>, ExportableEnti
provisionDeviceKey?: string; provisionDeviceKey?: string;
defaultRuleChainId?: RuleChainId; defaultRuleChainId?: RuleChainId;
defaultDashboardId?: DashboardId; defaultDashboardId?: DashboardId;
defaultQueueId?: QueueId; defaultQueueName?: string;
firmwareId?: OtaPackageId; firmwareId?: OtaPackageId;
softwareId?: OtaPackageId; softwareId?: OtaPackageId;
profileData: DeviceProfileData; profileData: DeviceProfileData;

1
ui-ngx/src/app/shared/models/tenant.model.ts

@ -137,7 +137,6 @@ export interface TenantProfile extends BaseData<TenantProfileId> {
name: string; name: string;
description?: string; description?: string;
default?: boolean; default?: boolean;
isolatedTbCore?: boolean;
isolatedTbRuleEngine?: boolean; isolatedTbRuleEngine?: boolean;
profileData?: TenantProfileData; profileData?: TenantProfileData;
} }

2
ui-ngx/src/assets/locale/locale.constant-cs_CZ.json

@ -2550,9 +2550,7 @@
"tenant-required": "Tenant je povinný", "tenant-required": "Tenant je povinný",
"search": "Vyhledat tenanty", "search": "Vyhledat tenanty",
"selected-tenants": "Vybráno { count, plural, 1 {1 tenantů} other {# tenantů} }", "selected-tenants": "Vybráno { count, plural, 1 {1 tenantů} other {# tenantů} }",
"isolated-tb-core": "Zpracování v izolovaném kontejneru ThingsBoard Core",
"isolated-tb-rule-engine": "Zpracování v izolovaném kontejneru ThingsBoard Rule Engine", "isolated-tb-rule-engine": "Zpracování v izolovaném kontejneru ThingsBoard Rule Engine",
"isolated-tb-core-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta",
"isolated-tb-rule-engine-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta" "isolated-tb-rule-engine-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta"
}, },
"tenant-profile": { "tenant-profile": {

2
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3053,9 +3053,7 @@
"tenant-required": "Tenant is required", "tenant-required": "Tenant is required",
"search": "Search tenants", "search": "Search tenants",
"selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } selected", "selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } selected",
"isolated-tb-core": "Processing in isolated ThingsBoard Core container",
"isolated-tb-rule-engine": "Processing in isolated ThingsBoard Rule Engine container", "isolated-tb-rule-engine": "Processing in isolated ThingsBoard Rule Engine container",
"isolated-tb-core-details": "Requires separate microservice(s) per isolated Tenant",
"isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant" "isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant"
}, },
"tenant-profile": { "tenant-profile": {

2
ui-ngx/src/assets/locale/locale.constant-es_ES.json

@ -3029,9 +3029,7 @@
"tenant-required": "Propietario requerido", "tenant-required": "Propietario requerido",
"search": "Buscar propietarios", "search": "Buscar propietarios",
"selected-tenants": "{ count, plural, 1 {1 propietario} other {# propietarios} } seleccionados", "selected-tenants": "{ count, plural, 1 {1 propietario} other {# propietarios} } seleccionados",
"isolated-tb-core": "Procesando en contenedor aislado",
"isolated-tb-rule-engine": "Procesando en contenedor Motor de Reglas aislado", "isolated-tb-rule-engine": "Procesando en contenedor Motor de Reglas aislado",
"isolated-tb-core-details": "Requiere microservicios separados por propietario aislado",
"isolated-tb-rule-engine-details": "Requiere microservicios separados por propietario aislado" "isolated-tb-rule-engine-details": "Requiere microservicios separados por propietario aislado"
}, },
"tenant-profile": { "tenant-profile": {

2
ui-ngx/src/assets/locale/locale.constant-ko_KR.json

@ -1997,9 +1997,7 @@
"tenant-required": "테넌트가 필요합니다.", "tenant-required": "테넌트가 필요합니다.",
"search": "테넌트 검색", "search": "테넌트 검색",
"selected-tenants": "{ count, plural, 1 {1 개 테넌트} other {# 개 테넌트} } 선택됨", "selected-tenants": "{ count, plural, 1 {1 개 테넌트} other {# 개 테넌트} } 선택됨",
"isolated-tb-core": "Processing in isolated ThingsBoard Core container",
"isolated-tb-rule-engine": "Processing in isolated ThingsBoard Rule Engine container", "isolated-tb-rule-engine": "Processing in isolated ThingsBoard Rule Engine container",
"isolated-tb-core-details": "Requires separate microservice(s) per isolated Tenant",
"isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant" "isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant"
}, },
"tenant-profile": { "tenant-profile": {

2
ui-ngx/src/assets/locale/locale.constant-pt_BR.json

@ -1659,9 +1659,7 @@
"tenant-required": "O locatário é obrigatório", "tenant-required": "O locatário é obrigatório",
"search": "Pesquisar locatários", "search": "Pesquisar locatários",
"selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } selecionado(s)", "selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } selecionado(s)",
"isolated-tb-core": "Processamento em contêiner isolado do ThingsBoard Core",
"isolated-tb-rule-engine": "Processamento em contêiner isolado do ThingsBoard Rule Engine", "isolated-tb-rule-engine": "Processamento em contêiner isolado do ThingsBoard Rule Engine",
"isolated-tb-core-details": "Exige microsserviço(s) separado(s) para cada locatário isolado",
"isolated-tb-rule-engine-details": "Exige microsserviço(s) separado(s) para cada locatário isolado" "isolated-tb-rule-engine-details": "Exige microsserviço(s) separado(s) para cada locatário isolado"
}, },
"timeinterval": { "timeinterval": {

2
ui-ngx/src/assets/locale/locale.constant-sl_SI.json

@ -1997,9 +1997,7 @@
"tenant-required": "Najemnik je obvezen", "tenant-required": "Najemnik je obvezen",
"search": "Iskanje najemnikov", "search": "Iskanje najemnikov",
"selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } izbran", "selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } izbran",
"isolated-tb-core": "Obdelava v izoliranem odlagališču ThingsBoard Core",
"isolated-tb-rule-engine": "Obdelava v izoliranem odlagališču ThingsBoard Rule Engine", "isolated-tb-rule-engine": "Obdelava v izoliranem odlagališču ThingsBoard Rule Engine",
"isolated-tb-core-details": "Zahteva ločene mikro storitve na izoliranega najemnika",
"isolated-tb-rule-engine-details": "Zahteva ločene mikro storitve na izoliranega najemnika" "isolated-tb-rule-engine-details": "Zahteva ločene mikro storitve na izoliranega najemnika"
}, },
"tenant-profile": { "tenant-profile": {

2
ui-ngx/src/assets/locale/locale.constant-tr_TR.json

@ -2569,9 +2569,7 @@
"tenant-required": "Tenant gerekli", "tenant-required": "Tenant gerekli",
"search": "Tenantları ara", "search": "Tenantları ara",
"selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenant} } seçildi", "selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenant} } seçildi",
"isolated-tb-core": "ThingsBoard soyutlanmış merkezi konteynerda işlensin",
"isolated-tb-rule-engine": "ThingsBoard soyutlanmış kural yönetimi konteynerda işlensin", "isolated-tb-rule-engine": "ThingsBoard soyutlanmış kural yönetimi konteynerda işlensin",
"isolated-tb-core-details": "Her soyutlanmış tenant ayrı bir mikro servis gerektirir",
"isolated-tb-rule-engine-details": "Her soyutlanmış tenant ayrı bir mikro servis gerektirir" "isolated-tb-rule-engine-details": "Her soyutlanmış tenant ayrı bir mikro servis gerektirir"
}, },
"tenant-profile": { "tenant-profile": {

2
ui-ngx/src/assets/locale/locale.constant-zh_CN.json

@ -2476,8 +2476,6 @@
"details": "详情", "details": "详情",
"events": "事件", "events": "事件",
"idCopiedMessage": "租户ID已经复制到粘贴板", "idCopiedMessage": "租户ID已经复制到粘贴板",
"isolated-tb-core": "隔离板芯容器中的加工",
"isolated-tb-core-details": "每个独立租户需要单独的微服务",
"isolated-tb-rule-engine": "在独立的ThingsBoard规则引擎容器中处理", "isolated-tb-rule-engine": "在独立的ThingsBoard规则引擎容器中处理",
"isolated-tb-rule-engine-details": "每个独立租户需要单独的微服务", "isolated-tb-rule-engine-details": "每个独立租户需要单独的微服务",
"manage-tenant-admins": "管理租户管理员", "manage-tenant-admins": "管理租户管理员",

Loading…
Cancel
Save