From 4512185cad02848fc1f6976e209ad7035e2598e6 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 18 Feb 2022 16:41:24 +0200 Subject: [PATCH 01/58] created Queue entity, dao and ui --- .../server/controller/BaseController.java | 18 +- .../server/controller/QueueController.java | 94 ++++- .../service/security/permission/Resource.java | 3 +- .../permission/SysAdminPermissions.java | 1 + .../permission/TenantAdminPermissions.java | 1 + .../routing/HashPartitionServiceTest.java | 7 +- .../server/queue/TbQueueAdmin.java | 2 + ...{QueueService.java => TbQueueService.java} | 2 +- .../server/dao/queue/QueueService.java | 48 +++ .../server/common/data/EntityType.java | 2 +- .../server/common/data/TenantProfile.java | 6 +- .../common/data/id/EntityIdFactory.java | 2 + .../server/common/data/id/QueueId.java | 43 +++ .../common/data/queue/ProcessingStrategy.java | 27 ++ .../data/queue/ProcessingStrategyType.java | 36 ++ .../server/common/data/queue/Queue.java | 42 +++ .../common/data/queue/SubmitStrategy.java | 24 ++ .../common/data/queue/SubmitStrategyType.java | 20 ++ ...ervice.java => DefaultTbQueueService.java} | 2 +- .../queue/discovery/HashPartitionService.java | 8 +- .../dao/device/DeviceProfileServiceImpl.java | 4 +- .../server/dao/model/ModelConstants.java | 16 + .../server/dao/model/sql/QueueEntity.java | 105 ++++++ .../dao/model/sql/TenantProfileEntity.java | 12 +- .../server/dao/queue/BaseQueueService.java | 333 ++++++++++++++++++ .../server/dao/queue/QueueDao.java | 38 ++ .../server/dao/sql/queue/JpaQueueDao.java | 86 +++++ .../server/dao/sql/queue/QueueRepository.java | 42 +++ .../server/dao/tenant/TenantServiceImpl.java | 5 + .../main/resources/sql/schema-entities.sql | 15 + ui-ngx/src/app/app.component.ts | 11 + ui-ngx/src/app/core/http/queue.service.ts | 25 +- ui-ngx/src/app/core/services/menu.service.ts | 18 +- .../profile/tenant-profile.component.html | 30 ++ .../profile/tenant-profile.component.ts | 18 + .../home/pages/admin/admin-routing.module.ts | 20 +- .../modules/home/pages/admin/admin.module.ts | 4 +- .../pages/admin/queue/queue.component.html | 182 ++++++++++ .../pages/admin/queue/queue.component.scss | 59 ++++ .../home/pages/admin/queue/queue.component.ts | 154 ++++++++ .../queue/queues-table-config.resolver.ts | 115 ++++++ .../queue/queue-type-list.component.html | 4 +- .../queue/queue-type-list.component.ts | 2 +- ui-ngx/src/app/shared/models/constants.ts | 3 +- .../app/shared/models/entity-type.models.ts | 18 +- ui-ngx/src/app/shared/models/id/queue-id.ts | 26 ++ ui-ngx/src/app/shared/models/queue.models.ts | 40 +++ ui-ngx/src/app/shared/models/tenant.model.ts | 2 + .../assets/locale/locale.constant-en_US.json | 65 +++- 49 files changed, 1801 insertions(+), 39 deletions(-) rename common/cluster-api/src/main/java/org/thingsboard/server/queue/{QueueService.java => TbQueueService.java} (96%) create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategyType.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategy.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategyType.java rename common/queue/src/main/java/org/thingsboard/server/queue/{DefaultQueueService.java => DefaultTbQueueService.java} (97%) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/queue/QueueDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/queue/QueueRepository.java create mode 100644 ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss create mode 100644 ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts create mode 100644 ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts create mode 100644 ui-ngx/src/app/shared/models/id/queue-id.ts diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f945cc30b7..1dafef871a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -70,6 +70,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.RpcId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TbResourceId; @@ -86,6 +87,7 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rpc.Rpc; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; @@ -108,6 +110,7 @@ import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; import org.thingsboard.server.dao.oauth2.OAuth2Service; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rpc.RpcService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -271,6 +274,9 @@ public abstract class BaseController { @Autowired protected EntityActionService entityActionService; + @Autowired + protected QueueService queueService; + @Value("${server.log_controller_error_stack_trace}") @Getter private boolean logControllerErrorStackTrace; @@ -516,6 +522,9 @@ public abstract class BaseController { case OTA_PACKAGE: checkOtaPackageId(new OtaPackageId(entityId.getId()), operation); return; + case QUEUE: + checkQueueId(new QueueId(entityId.getId()), operation); + return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); } @@ -807,7 +816,14 @@ public abstract class BaseController { } } - @SuppressWarnings("unchecked") + protected Queue checkQueueId(QueueId queueId, Operation operation) throws ThingsboardException { + validateId(queueId, "Incorrect queueId " + queueId); + Queue queue = queueService.findQueueById(getCurrentUser().getTenantId(), queueId); + checkNotNull(queue); + accessControlService.checkPermission(getCurrentUser(), Resource.QUEUE, operation, queueId, queue); + return queue; + } + protected I emptyId(EntityType entityType) { return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); } diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index 33cf7b5a0f..fef6fb9027 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -20,17 +20,26 @@ import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; -import org.thingsboard.server.queue.QueueService; +import org.thingsboard.server.queue.TbQueueService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.permission.Resource; import java.util.Set; +import java.util.UUID; import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_DESCRIPTION; @@ -42,7 +51,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHO @RequiredArgsConstructor public class QueueController extends BaseController { - private final QueueService queueService; + private final TbQueueService tbQueueService; @ApiOperation(value = "Get queue names (getTenantQueuesByServiceType)", notes = "Returns a set of unique queue names based on service type. " + TENANT_AUTHORITY_PARAGRAPH) @@ -53,7 +62,86 @@ public class QueueController extends BaseController { @RequestParam String serviceType) throws ThingsboardException { checkParameter("serviceType", serviceType); try { - return queueService.getQueuesByServiceType(ServiceType.valueOf(serviceType)); + //TODO: replace for using new QueueService + return tbQueueService.getQueuesByServiceType(ServiceType.valueOf(serviceType)); + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @RequestMapping(value = "/tenant/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET) + @ResponseBody + public PageData getTenantQueuesByServiceType(@RequestParam String serviceType, + @RequestParam int pageSize, + @RequestParam int page, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String sortProperty, + @RequestParam(required = false) String sortOrder) throws ThingsboardException { + checkParameter("serviceType", serviceType); + try { + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); + ServiceType type = ServiceType.valueOf(serviceType); + switch (type) { + case TB_RULE_ENGINE: + return queueService.findQueuesByTenantId(getTenantId(), pageLink); + default: + return new PageData<>(); + } + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @RequestMapping(value = "/tenant/queues/{queueId}", method = RequestMethod.GET) + @ResponseBody + public Queue getQueueById(@PathVariable("queueId") String queueIdStr) throws ThingsboardException { + checkParameter("queueId", queueIdStr); + try { + QueueId queueId = new QueueId(UUID.fromString(queueIdStr)); + return checkNotNull(queueService.findQueueById(getTenantId(), queueId)); + } catch ( + Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @RequestMapping(value = "/tenant/queues", params = {"serviceType"}, method = RequestMethod.POST) + @ResponseBody + public Queue saveQueue(@RequestBody Queue queue, + @RequestParam String serviceType) throws ThingsboardException { + checkParameter("serviceType", serviceType); + try { + queue.setTenantId(getCurrentUser().getTenantId()); + + checkEntity(queue.getId(), queue, Resource.QUEUE); + + ServiceType type = ServiceType.valueOf(serviceType); + switch (type) { + case TB_RULE_ENGINE: + queue.setTenantId(getTenantId()); + Queue savedQueue = queueService.saveQueue(queue); + checkNotNull(savedQueue); + return savedQueue; + default: + return null; + } + } catch (Exception e) { + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @RequestMapping(value = "/tenant/queues/{queueId}", method = RequestMethod.DELETE) + @ResponseBody + public void deleteQueue(@PathVariable("queueId") String queueIdStr) throws ThingsboardException { + checkParameter("queueId", queueIdStr); + try { + QueueId queueId = new QueueId(toUUID(queueIdStr)); + checkQueueId(queueId, Operation.DELETE); + queueService.deleteQueue(getTenantId(), queueId); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java index 1414afe232..f86680f156 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java @@ -40,7 +40,8 @@ public enum Resource { TB_RESOURCE(EntityType.TB_RESOURCE), OTA_PACKAGE(EntityType.OTA_PACKAGE), EDGE(EntityType.EDGE), - RPC(EntityType.RPC); + RPC(EntityType.RPC), + QUEUE(EntityType.QUEUE); private final EntityType entityType; diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java index ca33716692..20e2001c87 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java @@ -39,6 +39,7 @@ public class SysAdminPermissions extends AbstractPermissions { put(Resource.OAUTH2_CONFIGURATION_TEMPLATE, PermissionChecker.allowAllPermissionChecker); put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker); put(Resource.TB_RESOURCE, systemEntityPermissionChecker); + put(Resource.QUEUE, systemEntityPermissionChecker); } private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() { diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java index 4ff884f0e1..bcc6251315 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java @@ -45,6 +45,7 @@ public class TenantAdminPermissions extends AbstractPermissions { put(Resource.OTA_PACKAGE, tenantEntityPermissionChecker); put(Resource.EDGE, tenantEntityPermissionChecker); put(Resource.RPC, tenantEntityPermissionChecker); + put(Resource.QUEUE, tenantEntityPermissionChecker); } public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() { diff --git a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java index d304a567ab..09fe580661 100644 --- a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java @@ -21,13 +21,12 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.context.ApplicationEventPublisher; import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.queue.QueueService; +import org.thingsboard.server.queue.TbQueueService; import org.thingsboard.server.queue.discovery.HashPartitionService; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; @@ -59,7 +58,7 @@ public class HashPartitionServiceTest { private TenantRoutingInfoService routingInfoService; private ApplicationEventPublisher applicationEventPublisher; private TbQueueRuleEngineSettings ruleEngineSettings; - private QueueService queueService; + private TbQueueService queueService; private String hashFunctionName = "sha256"; @@ -70,7 +69,7 @@ public class HashPartitionServiceTest { applicationEventPublisher = mock(ApplicationEventPublisher.class); routingInfoService = mock(TenantRoutingInfoService.class); ruleEngineSettings = mock(TbQueueRuleEngineSettings.class); - queueService = mock(QueueService.class); + queueService = mock(TbQueueService.class); clusterRoutingService = new HashPartitionService(discoveryService, routingInfoService, applicationEventPublisher, diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java index 6a581d522e..37c99dfccb 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java @@ -20,4 +20,6 @@ public interface TbQueueAdmin { void createTopicIfNotExists(String topic); void destroy(); + + default void deleteTopic(String topic) { } } diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/QueueService.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueService.java similarity index 96% rename from common/cluster-api/src/main/java/org/thingsboard/server/queue/QueueService.java rename to common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueService.java index 08155caf60..bc7964df7e 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/QueueService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueService.java @@ -19,7 +19,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import java.util.Set; -public interface QueueService { +public interface TbQueueService { Set getQueuesByServiceType(ServiceType serviceType); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java new file mode 100644 index 0000000000..edb51fa2a3 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java @@ -0,0 +1,48 @@ +/** + * 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.dao.queue; + +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; + +import java.util.List; + +public interface QueueService { + + Queue saveQueue(Queue queue); + + void deleteQueue(TenantId tenantId, QueueId queueId); + + List findQueuesByTenantId(TenantId tenantId); + + PageData findQueuesByTenantId(TenantId tenantId, PageLink pageLink); + + List findAllMainQueues(); + + List findAllQueues(); + + Queue findQueueById(TenantId tenantId, QueueId queueId); + + Queue findQueueByTenantIdAndName(TenantId tenantId, String name); + + Queue createDefaultMainQueue(TenantProfile tenantProfile, TenantId tenantId); + + void deleteQueuesByTenantId(TenantId tenantId); +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 33a5753465..1ef5bb433a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -19,5 +19,5 @@ package org.thingsboard.server.common.data; * @author Andrew Shvayka */ public enum EntityType { - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE, RPC; + TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE, RPC, QUEUE; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java index 27cc52ba9f..32b6ba88ba 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java @@ -57,7 +57,11 @@ public class TenantProfile extends SearchTextBased implements H @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") private boolean isolatedTbRuleEngine; - @ApiModelProperty(position = 8, value = "Complex JSON object that contains profile settings: max devices, max assets, rate limits, etc.") + @ApiModelProperty(position = 8, value = "Max amount of queues configurable by isolated tenant.", example = "5") + private Integer maxNumberOfQueues; + @ApiModelProperty(position = 9, value = "Max amount of partitions per queue configurable by isolated tenant.", example = "10") + private Integer maxNumberOfPartitionsPerQueue; + @ApiModelProperty(position = 10, value = "Complex JSON object that contains profile settings: max devices, max assets, rate limits, etc.") private transient TenantProfileData profileData; @JsonIgnore private byte[] profileDataBytes; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java index ad91dc8d88..8bd13b7c3f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java @@ -77,6 +77,8 @@ public class EntityIdFactory { return new EdgeId(uuid); case RPC: return new RpcId(uuid); + case QUEUE: + return new QueueId(uuid); } throw new IllegalArgumentException("EntityType " + type + " is not supported!"); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java new file mode 100644 index 0000000000..37a4136d46 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java @@ -0,0 +1,43 @@ +/** + * 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.common.data.id; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.thingsboard.server.common.data.EntityType; + +import java.util.UUID; + +public class QueueId extends UUIDBased implements EntityId { + + private static final long serialVersionUID = 1L; + + @JsonCreator + public QueueId(@JsonProperty("id") UUID id) { + super(id); + } + + public static QueueId fromString(String queueId) { + return new QueueId(UUID.fromString(queueId)); + } + + @JsonIgnore + @Override + public EntityType getEntityType() { + return EntityType.QUEUE; + } +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java new file mode 100644 index 0000000000..8a315f14ad --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java @@ -0,0 +1,27 @@ +/** + * 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.common.data.queue; + +import lombok.Data; + +@Data +public class ProcessingStrategy { + private ProcessingStrategyType type; + private int retries; + private double failurePercentage; + private long pauseBetweenRetries; + private long maxPauseBetweenRetries; +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategyType.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategyType.java new file mode 100644 index 0000000000..7a367a2141 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategyType.java @@ -0,0 +1,36 @@ +/** + * 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. + */ + +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.queue; + +public enum ProcessingStrategyType { + SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java new file mode 100644 index 0000000000..84776c88f4 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.queue; + +import lombok.Data; +import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.HasName; +import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +public class Queue extends BaseData implements HasName, HasTenantId { + private TenantId tenantId; + private String name; + private String topic; + private int pollInterval; + private int partitions; + private long packProcessingTimeout; + private SubmitStrategy submitStrategy; + private ProcessingStrategy processingStrategy; + + public Queue() { + } + + public Queue(QueueId id) { + super(id); + } +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategy.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategy.java new file mode 100644 index 0000000000..972433b038 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategy.java @@ -0,0 +1,24 @@ +/** + * 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.common.data.queue; + +import lombok.Data; + +@Data +public class SubmitStrategy { + private SubmitStrategyType type; + private int batchSize; +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategyType.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategyType.java new file mode 100644 index 0000000000..cb6e2989e5 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/SubmitStrategyType.java @@ -0,0 +1,20 @@ +/** + * 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.common.data.queue; + +public enum SubmitStrategyType { + BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL +} \ No newline at end of file diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultQueueService.java b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java similarity index 97% rename from common/queue/src/main/java/org/thingsboard/server/queue/DefaultQueueService.java rename to common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java index 427e2c1f1a..5a0e540ac4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultQueueService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java @@ -31,7 +31,7 @@ import java.util.stream.Collectors; @Service @RequiredArgsConstructor -public class DefaultQueueService implements QueueService { +public class DefaultTbQueueService implements TbQueueService { private final TbQueueRuleEngineSettings ruleEngineSettings; private Set ruleEngineQueues; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 7478d21816..4882a96f72 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -16,13 +16,11 @@ package org.thingsboard.server.queue.discovery; import com.google.common.hash.HashFunction; -import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceQueue; @@ -31,7 +29,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; -import org.thingsboard.server.queue.QueueService; +import org.thingsboard.server.queue.TbQueueService; import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; @@ -66,7 +64,7 @@ public class HashPartitionService implements PartitionService { private final TbServiceInfoProvider serviceInfoProvider; private final TenantRoutingInfoService tenantRoutingInfoService; private final TbQueueRuleEngineSettings tbQueueRuleEngineSettings; - private final QueueService queueService; + private final TbQueueService queueService; private final ConcurrentMap partitionTopics = new ConcurrentHashMap<>(); private final ConcurrentMap partitionSizes = new ConcurrentHashMap<>(); private final ConcurrentMap tenantRoutingInfoMap = new ConcurrentHashMap<>(); @@ -85,7 +83,7 @@ public class HashPartitionService implements PartitionService { TenantRoutingInfoService tenantRoutingInfoService, ApplicationEventPublisher applicationEventPublisher, TbQueueRuleEngineSettings tbQueueRuleEngineSettings, - QueueService queueService) { + TbQueueService queueService) { this.serviceInfoProvider = serviceInfoProvider; this.tenantRoutingInfoService = tenantRoutingInfoService; this.applicationEventPublisher = applicationEventPublisher; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 9a272b4739..35d4dc2899 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -82,7 +82,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TenantDao; -import org.thingsboard.server.queue.QueueService; +import org.thingsboard.server.queue.TbQueueService; import java.util.Arrays; import java.util.Collections; @@ -115,7 +115,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } @Autowired(required = false) - private QueueService queueService; + private TbQueueService queueService; @Autowired private DeviceProfileDao deviceProfileDao; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 8f692d5a12..cb209c2ee7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -128,6 +128,8 @@ public class ModelConstants { public static final String TENANT_PROFILE_IS_DEFAULT_PROPERTY = "is_default"; public static final String TENANT_PROFILE_ISOLATED_TB_CORE = "isolated_tb_core"; public static final String TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE = "isolated_tb_rule_engine"; + public static final String TENANT_PROFILE_MAX_NUMBER_OF_QUEUES = "max_number_of_queues"; + public static final String TENANT_PROFILE_MAX_NUMBER_OF_PARTITIONS_PER_QUEUE = "max_number_of_partitions_per_queue"; /** * Cassandra customer constants. @@ -581,6 +583,20 @@ public class ModelConstants { public static final String DOUBLE_VALUE_COLUMN = "dbl_v"; public static final String JSON_VALUE_COLUMN = "json_v"; + /** + * Queue constants. + */ + + public static final String QUEUE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; + public static final String QUEUE_NAME_PROPERTY = "name"; + public static final String QUEUE_TOPIC_PROPERTY = "topic"; + public static final String QUEUE_POLL_INTERVAL_PROPERTY = "poll_interval"; + public static final String QUEUE_PARTITIONS_PROPERTY = "partitions"; + public static final String QUEUE_PACK_PROCESSING_TIMEOUT_PROPERTY = "pack_processing_timeout"; + public static final String QUEUE_SUBMIT_STRATEGY_PROPERTY = "submit_strategy"; + public static final String QUEUE_PROCESSING_STRATEGY_PROPERTY = "processing_strategy"; + public static final String QUEUE_COLUMN_FAMILY_NAME = "queue"; + protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, JSON_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; protected static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN), count(JSON_VALUE_COLUMN)}; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java new file mode 100644 index 0000000000..3791ab4ac3 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java @@ -0,0 +1,105 @@ +/** + * 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.dao.model.sql; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.data.queue.SubmitStrategy; +import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.model.BaseSqlEntity; +import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.util.mapping.JsonStringType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.util.UUID; + +@Data +@EqualsAndHashCode(callSuper = true) +@Entity +@TypeDef(name = "json", typeClass = JsonStringType.class) +@Table(name = ModelConstants.QUEUE_COLUMN_FAMILY_NAME) +public class QueueEntity extends BaseSqlEntity { + + private static final ObjectMapper mapper = new ObjectMapper(); + + @Column(name = ModelConstants.QUEUE_TENANT_ID_PROPERTY) + private UUID tenantId; + + @Column(name = ModelConstants.QUEUE_NAME_PROPERTY) + private String name; + + @Column(name = ModelConstants.QUEUE_TOPIC_PROPERTY) + private String topic; + @Column(name = ModelConstants.QUEUE_POLL_INTERVAL_PROPERTY) + private int pollInterval; + + @Column(name = ModelConstants.QUEUE_PARTITIONS_PROPERTY) + private int partitions; + + @Column(name = ModelConstants.QUEUE_PACK_PROCESSING_TIMEOUT_PROPERTY) + private long packProcessingTimeout; + + @Type(type = "json") + @Column(name = ModelConstants.QUEUE_SUBMIT_STRATEGY_PROPERTY) + private JsonNode submitStrategy; + + @Type(type = "json") + @Column(name = ModelConstants.QUEUE_PROCESSING_STRATEGY_PROPERTY) + private JsonNode processingStrategy; + + public QueueEntity() { + } + + public QueueEntity(Queue queue) { + if (queue.getId() != null) { + this.setId(queue.getId().getId()); + } + this.createdTime = queue.getCreatedTime(); + this.tenantId = DaoUtil.getId(queue.getTenantId()); + this.name = queue.getName(); + this.topic = queue.getTopic(); + this.pollInterval = queue.getPollInterval(); + this.partitions = queue.getPartitions(); + this.packProcessingTimeout = queue.getPackProcessingTimeout(); + this.submitStrategy = mapper.valueToTree(queue.getSubmitStrategy()); + this.processingStrategy = mapper.valueToTree(queue.getProcessingStrategy()); + } + + @Override + public Queue toData() { + Queue queue = new Queue(new QueueId(getUuid())); + queue.setCreatedTime(createdTime); + queue.setTenantId(new TenantId(tenantId)); + queue.setName(name); + queue.setTopic(topic); + queue.setPollInterval(pollInterval); + queue.setPartitions(partitions); + queue.setPackProcessingTimeout(packProcessingTimeout); + queue.setSubmitStrategy(mapper.convertValue(this.submitStrategy, SubmitStrategy.class)); + queue.setProcessingStrategy(mapper.convertValue(this.processingStrategy, ProcessingStrategy.class)); + return queue; + } +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java index 8613c7ced5..2b62588c76 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java @@ -21,13 +21,13 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import javax.persistence.Column; @@ -59,6 +59,12 @@ public final class TenantProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE) private boolean isolatedTbRuleEngine; + @Column(name = ModelConstants.TENANT_PROFILE_MAX_NUMBER_OF_QUEUES) + private Integer maxNumberOfQueues; + + @Column(name = ModelConstants.TENANT_PROFILE_MAX_NUMBER_OF_PARTITIONS_PER_QUEUE) + private Integer maxNumberOfPartitionsPerQueue; + @Type(type = "jsonb") @Column(name = ModelConstants.TENANT_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode profileData; @@ -77,6 +83,8 @@ public final class TenantProfileEntity extends BaseSqlEntity impl this.isDefault = tenantProfile.isDefault(); this.isolatedTbCore = tenantProfile.isIsolatedTbCore(); this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine(); + this.maxNumberOfPartitionsPerQueue = tenantProfile.getMaxNumberOfPartitionsPerQueue(); + this.maxNumberOfQueues = tenantProfile.getMaxNumberOfQueues(); this.profileData = JacksonUtil.convertValue(tenantProfile.getProfileData(), ObjectNode.class); } @@ -103,6 +111,8 @@ public final class TenantProfileEntity extends BaseSqlEntity impl tenantProfile.setDefault(isDefault); tenantProfile.setIsolatedTbCore(isolatedTbCore); tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine); + tenantProfile.setMaxNumberOfPartitionsPerQueue(maxNumberOfPartitionsPerQueue); + tenantProfile.setMaxNumberOfQueues(maxNumberOfQueues); tenantProfile.setProfileData(JacksonUtil.convertValue(profileData, TenantProfileData.class)); return tenantProfile; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java new file mode 100644 index 0000000000..cad7f9cb48 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -0,0 +1,333 @@ +/** + * 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.dao.queue; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.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.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.service.PaginatedRemover; +import org.thingsboard.server.dao.service.Validator; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.queue.TbQueueAdmin; + +import java.util.List; + +@Service +@Slf4j +@RequiredArgsConstructor +public class BaseQueueService extends AbstractEntityService implements QueueService { + + @Autowired + private QueueDao queueDao; + + @Autowired + private TenantDao tenantDao; + + @Autowired + private TbTenantProfileCache tenantProfileCache; + + @Autowired(required = false) + private TbQueueAdmin tbQueueAdmin; + +// @Autowired(required = false) +// private TbQueueClusterService queueClusterService; + +// @Autowired +// private QueueStatsService queueStatsService; + + @Override + @Transactional + public Queue saveQueue(Queue queue) { + log.trace("Executing createOrUpdateQueue [{}]", queue); + queueValidator.validate(queue, Queue::getTenantId); + Queue savedQueue; + if (queue.getId() == null) { + savedQueue = createQueue(queue); + } else { + savedQueue = updateQueue(queue); + } + +// if (queueClusterService != null) { +// queueClusterService.onQueueChange(savedQueue, null); +// } + return savedQueue; + } + + private Queue createQueue(Queue queue) { + Queue createdQueue = queueDao.save(queue.getTenantId(), queue); + if (tbQueueAdmin != null) { + for (int i = 0; i < queue.getPartitions(); i++) { + tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + } + } + return createdQueue; + } + + private Queue updateQueue(Queue queue) { + Queue oldQueue = queueDao.findById(queue.getTenantId(), queue.getUuidId()); + Queue updatedQueue = queueDao.save(queue.getTenantId(), queue); + + int oldPartitions = oldQueue.getPartitions(); + int currentPartitions = queue.getPartitions(); + + //TODO: 3.2 remove if partitions can't be deleted. +// if (currentPartitions != oldPartitions && tbQueueAdmin != null) { +// queueClusterService.onQueueDelete(queue, null); +// if (currentPartitions > oldPartitions) { +// log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); +// for (int i = oldPartitions; i < currentPartitions; i++) { +// tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); +// } +// } else { +// log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); +// for (int i = currentPartitions; i < oldPartitions; i++) { +// tbQueueAdmin.deleteTopic(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); +// } +// } +// } + + return updatedQueue; + } + + @Override + @Transactional + public void deleteQueue(TenantId tenantId, QueueId queueId) { + log.trace("Executing deleteQueue, queueId: [{}]", queueId); + Queue queue = findQueueById(tenantId, queueId); +// if (queueClusterService != null) { +// queueClusterService.onQueueDelete(queue, null); +// } +// queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); + boolean result = queueDao.removeById(tenantId, queueId.getId()); + if (result && tbQueueAdmin != null) { + for (int i = 0; i < queue.getPartitions(); i++) { + String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); + log.debug("Deleting queue [{}]", fullTopicName); + try { + tbQueueAdmin.deleteTopic(fullTopicName); + } catch (Exception e) { + log.error("Failed to delete queue [{}]", fullTopicName); + } + } + } + } + + @Override + public List findQueuesByTenantId(TenantId tenantId) { + log.trace("Executing findQueues, tenantId: [{}]", tenantId); + return queueDao.findAllByTenantId(getSystemOrIsolatedTenantId(tenantId)); + } + + @Override + public PageData findQueuesByTenantId(TenantId tenantId, PageLink pageLink) { + log.trace("Executing findQueues pageLink [{}]", pageLink); + Validator.validatePageLink(pageLink); + return queueDao.findQueuesByTenantId(getSystemOrIsolatedTenantId(tenantId), pageLink); + } + + @Override + public List findAllMainQueues() { + log.trace("Executing findAllMainQueues"); + return queueDao.findAllMainQueues(); + } + + @Override + public List findAllQueues() { + log.trace("Executing findAllQueues"); + return queueDao.findAllQueues(); + } + + @Override + public Queue findQueueById(TenantId tenantId, QueueId queueId) { + log.trace("Executing findQueueById, queueId: [{}]", queueId); + return queueDao.findById(tenantId, queueId.getId()); + } + + @Override + public Queue findQueueByTenantIdAndName(TenantId tenantId, String queueName) { + log.trace("Executing findQueueByTenantIdAndName, tenantId: [{}] queueName: [{}]", tenantId, queueName); + return queueDao.findQueueByTenantIdAndName(getSystemOrIsolatedTenantId(tenantId), queueName); + } + + @Override + public void deleteQueuesByTenantId(TenantId tenantId) { + Validator.validateId(tenantId, "Incorrect tenant id for delete queues request."); + tenantQueuesRemover.removeEntities(tenantId, tenantId); + } + + @Override + @Transactional + public Queue createDefaultMainQueue(TenantProfile tenantProfile, TenantId tenantId) { + Queue mainQueue = new Queue(); + mainQueue.setTenantId(tenantId); + mainQueue.setName("Main"); + mainQueue.setTopic("tb_rule_engine.main"); + mainQueue.setPollInterval(25); + mainQueue.setPartitions(Math.max(tenantProfile.getMaxNumberOfPartitionsPerQueue(), 1)); + mainQueue.setPackProcessingTimeout(60000); + SubmitStrategy mainQueueSubmitStrategy = new SubmitStrategy(); + mainQueueSubmitStrategy.setType(SubmitStrategyType.BURST); + mainQueueSubmitStrategy.setBatchSize(1000); + mainQueue.setSubmitStrategy(mainQueueSubmitStrategy); + ProcessingStrategy mainQueueProcessingStrategy = new ProcessingStrategy(); + mainQueueProcessingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES); + mainQueueProcessingStrategy.setRetries(3); + mainQueueProcessingStrategy.setFailurePercentage(0); + mainQueueProcessingStrategy.setPauseBetweenRetries(3); + mainQueueProcessingStrategy.setMaxPauseBetweenRetries(3); + mainQueue.setProcessingStrategy(mainQueueProcessingStrategy); + return saveQueue(mainQueue); + } + + private DataValidator queueValidator = + new DataValidator<>() { + + @Override + protected void validateCreate(TenantId tenantId, Queue queue) { + if (queueDao.findQueueByTenantIdAndTopic(tenantId, queue.getTopic()) != null) { + throw new DataValidationException(String.format("Queue with topic: %s already exists!", queue.getTopic())); + } + if (queueDao.findQueueByTenantIdAndName(tenantId, queue.getName()) != null) { + throw new DataValidationException(String.format("Queue with name: %s already exists!", queue.getName())); + } + } + + @Override + protected void validateUpdate(TenantId tenantId, Queue queue) { + Queue foundQueue = queueDao.findById(tenantId, queue.getUuidId()); + if (queueDao.findById(tenantId, queue.getUuidId()) == null) { + throw new DataValidationException(String.format("Queue with id: %s does not exists!", queue.getId())); + } + if (!foundQueue.getName().equals(queue.getName())) { + throw new DataValidationException("Queue name can't be changed!"); + } + if (!foundQueue.getTopic().equals(queue.getTopic())) { + throw new DataValidationException("Queue topic can't be changed!"); + } + } + + @Override + protected void validateDataImpl(TenantId tenantId, Queue queue) { + if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { + TenantProfile tenantProfile = tenantProfileCache.get(tenantId); + + if (!tenantProfile.isIsolatedTbRuleEngine()) { + throw new DataValidationException("Tenant should be isolated!"); + } + + if (queue.getId() == null) { + List existingQueues = findQueuesByTenantId(tenantId); + if (existingQueues.size() >= tenantProfile.getMaxNumberOfQueues()) { + throw new DataValidationException("The limit for creating new queue has been exceeded!"); + } + } + + if (queue.getPartitions() > tenantProfile.getMaxNumberOfPartitionsPerQueue()) { + throw new DataValidationException(String.format("Queue partitions can't be more then %d", tenantProfile.getMaxNumberOfPartitionsPerQueue())); + } + } + + if (StringUtils.isEmpty(queue.getName())) { + throw new DataValidationException("Queue name should be specified!"); + } + if (StringUtils.isBlank(queue.getTopic())) { + throw new DataValidationException("Queue topic should be non empty and without spaces!"); + } + if (queue.getPollInterval() < 1) { + throw new DataValidationException("Queue poll interval should be more then 0!"); + } + if (queue.getPartitions() < 1) { + throw new DataValidationException("Queue partitions should be more then 0!"); + } + if (queue.getPackProcessingTimeout() < 1) { + throw new DataValidationException("Queue pack processing timeout should be more then 0!"); + } + + SubmitStrategy submitStrategy = queue.getSubmitStrategy(); + if (submitStrategy == null) { + throw new DataValidationException("Queue submit strategy can't be null!"); + } + if (submitStrategy.getType() == null) { + throw new DataValidationException("Queue submit strategy type can't be null!"); + } + if (submitStrategy.getType() == SubmitStrategyType.BATCH && submitStrategy.getBatchSize() < 1) { + throw new DataValidationException("Queue submit strategy batch size should be more then 0!"); + } + ProcessingStrategy processingStrategy = queue.getProcessingStrategy(); + if (processingStrategy == null) { + throw new DataValidationException("Queue processing strategy can't be null!"); + } + if (processingStrategy.getType() == null) { + throw new DataValidationException("Queue processing strategy type can't be null!"); + } + if (processingStrategy.getRetries() < 0) { + throw new DataValidationException("Queue processing strategy retries can't be less then 0!"); + } + if (processingStrategy.getFailurePercentage() < 0 || processingStrategy.getFailurePercentage() > 100) { + throw new DataValidationException("Queue processing strategy failure percentage should be in a range from 0 to 100!"); + } + if (processingStrategy.getPauseBetweenRetries() < 0) { + throw new DataValidationException("Queue processing strategy pause between retries can't be less then 0!"); + } + if (processingStrategy.getMaxPauseBetweenRetries() < processingStrategy.getPauseBetweenRetries()) { + throw new DataValidationException("Queue processing strategy MAX pause between retries can't be less then pause between retries!"); + } + } + }; + + private PaginatedRemover tenantQueuesRemover = + new PaginatedRemover<>() { + + @Override + protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { + return queueDao.findQueuesByTenantId(id, pageLink); + } + + @Override + protected void removeEntity(TenantId tenantId, Queue entity) { + deleteQueue(tenantId, entity.getId()); + } + }; + + private TenantId getSystemOrIsolatedTenantId(TenantId tenantId) { + if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { + TenantProfile tenantProfile = tenantProfileCache.get(tenantId); + if (tenantProfile.isIsolatedTbRuleEngine()) { + return tenantId; + } + } + + return TenantId.SYS_TENANT_ID; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/QueueDao.java b/dao/src/main/java/org/thingsboard/server/dao/queue/QueueDao.java new file mode 100644 index 0000000000..5cc7a5d7ba --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/QueueDao.java @@ -0,0 +1,38 @@ +/** + * 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.dao.queue; + +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.dao.Dao; + +import java.util.List; + +public interface QueueDao extends Dao { + Queue findQueueByTenantIdAndTopic(TenantId tenantId, String topic); + + Queue findQueueByTenantIdAndName(TenantId tenantId, String name); + + List findAllMainQueues(); + + List findAllQueues(); + + List findAllByTenantId(TenantId tenantId); + + PageData findQueuesByTenantId(TenantId tenantId, PageLink pageLink); +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java new file mode 100644 index 0000000000..4e544f35cd --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/queue/JpaQueueDao.java @@ -0,0 +1,86 @@ +/** + * 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.dao.sql.queue; + +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.model.sql.QueueEntity; +import org.thingsboard.server.dao.queue.QueueDao; +import org.thingsboard.server.dao.sql.JpaAbstractDao; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@Slf4j +@Component +public class JpaQueueDao extends JpaAbstractDao implements QueueDao { + + @Autowired + private QueueRepository queueRepository; + + @Override + protected Class getEntityClass() { + return QueueEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return queueRepository; + } + + @Override + public Queue findQueueByTenantIdAndTopic(TenantId tenantId, String topic) { + return DaoUtil.getData(queueRepository.findByTenantIdAndTopic(tenantId.getId(), topic)); + } + + @Override + public Queue findQueueByTenantIdAndName(TenantId tenantId, String name) { + return DaoUtil.getData(queueRepository.findByTenantIdAndName(tenantId.getId(), name)); + } + + @Override + public List findAllByTenantId(TenantId tenantId) { + List entities = queueRepository.findByTenantId(tenantId.getId()); + return DaoUtil.convertDataList(entities); + } + + @Override + public List findAllMainQueues() { + List entities = Lists.newArrayList(queueRepository.findAllByName("Main")); + return DaoUtil.convertDataList(entities); + } + + @Override + public List findAllQueues() { + List entities = Lists.newArrayList(queueRepository.findAll()); + return DaoUtil.convertDataList(entities); + } + + @Override + public PageData findQueuesByTenantId(TenantId tenantId, PageLink pageLink) { + return DaoUtil.toPageData(queueRepository + .findByTenantId(tenantId.getId(), Objects.toString(pageLink.getTextSearch(), ""), DaoUtil.toPageable(pageLink))); + } +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/queue/QueueRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/queue/QueueRepository.java new file mode 100644 index 0000000000..d531072a39 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/queue/QueueRepository.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sql.queue; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.thingsboard.server.dao.model.sql.QueueEntity; + +import java.util.List; +import java.util.UUID; + +public interface QueueRepository extends CrudRepository { + QueueEntity findByTenantIdAndTopic(UUID tenantId, String topic); + + QueueEntity findByTenantIdAndName(UUID tenantId, String name); + + List findByTenantId(UUID tenantId); + + @Query("SELECT q FROM QueueEntity q WHERE q.tenantId = :tenantId " + + "AND LOWER(q.name) LIKE LOWER(CONCAT(:textSearch, '%'))") + Page findByTenantId(@Param("tenantId") UUID tenantId, + @Param("textSearch") String textSearch, + Pageable pageable); + + List findAllByName(String name); +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 056f5987d8..2ae46df19a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -37,6 +37,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.rpc.RpcService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -104,6 +105,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Autowired private RpcService rpcService; + @Autowired + private QueueService queueService; + @Override public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); @@ -160,6 +164,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe resourceService.deleteResourcesByTenantId(tenantId); otaPackageService.deleteOtaPackagesByTenantId(tenantId); rpcService.deleteAllRpcByTenantId(tenantId); + queueService.deleteQueuesByTenantId(tenantId); tenantDao.removeById(tenantId, tenantId.getId()); deleteEntityRelations(tenantId, tenantId); } diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index cdae84fe15..5335ce6f5f 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -337,6 +337,8 @@ CREATE TABLE IF NOT EXISTS tenant_profile ( is_default boolean, isolated_tb_core boolean, isolated_tb_rule_engine boolean, + max_number_of_queues int , + max_number_of_partitions_per_queue int, CONSTRAINT tenant_profile_name_unq_key UNIQUE (name) ); @@ -632,6 +634,19 @@ CREATE TABLE IF NOT EXISTS rpc ( status varchar(255) NOT NULL ); +CREATE TABLE IF NOT EXISTS queue( + id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY, + created_time bigint NOT NULL, + tenant_id uuid, + name varchar(255), + topic varchar(255), + poll_interval int, + partitions int, + pack_processing_timeout bigint, + submit_strategy varchar(255), + processing_strategy varchar(255) +); + CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint) LANGUAGE plpgsql AS $$ diff --git a/ui-ngx/src/app/app.component.ts b/ui-ngx/src/app/app.component.ts index 9f914dda59..0864e2e8ed 100644 --- a/ui-ngx/src/app/app.component.ts +++ b/ui-ngx/src/app/app.component.ts @@ -78,6 +78,17 @@ export class AppComponent implements OnInit { ) ); + this.matIconRegistry.addSvgIconLiteral( + 'queues-list', + this.domSanitizer.bypassSecurityTrustHtml( + '' + + '' + + '' + + '' + + '' + ) + ); + this.storageService.testLocalStorage(); this.setupTranslate(); diff --git a/ui-ngx/src/app/core/http/queue.service.ts b/ui-ngx/src/app/core/http/queue.service.ts index 5aae5fe561..dc98c15d39 100644 --- a/ui-ngx/src/app/core/http/queue.service.ts +++ b/ui-ngx/src/app/core/http/queue.service.ts @@ -18,7 +18,9 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; import { Observable } from 'rxjs'; -import { ServiceType } from '@shared/models/queue.models'; +import { QueueInfo, ServiceType } from '@shared/models/queue.models'; +import { PageLink } from '@shared/models/page/page-link'; +import { PageData } from '@shared/models/page/page-data'; @Injectable({ providedIn: 'root' @@ -29,8 +31,27 @@ export class QueueService { private http: HttpClient ) { } - public getTenantQueuesByServiceType(serviceType: ServiceType, config?: RequestConfig): Observable> { + public getTenantQueuesNamesByServiceType(serviceType: ServiceType, config?: RequestConfig): Observable> { return this.http.get>(`/api/tenant/queues?serviceType=${serviceType}`, defaultHttpOptionsFromConfig(config)); } + + public getQueueById(queueId: string): Observable { + return this.http.get(`/api/tenant/queues/${queueId}`); + } + + public getTenantQueuesByServiceType(pageLink: PageLink, + serviceType: ServiceType, + config?: RequestConfig): Observable> { + return this.http.get>(`/api/tenant/queues${pageLink.toQuery()}&serviceType=${serviceType}`, + defaultHttpOptionsFromConfig(config)); + } + + public saveQueue(queue: QueueInfo, serviceType: ServiceType, config?: RequestConfig): Observable { + return this.http.post(`/api/tenant/queues?serviceType=${serviceType}`, queue, defaultHttpOptionsFromConfig(config)); + } + + public deleteQueue(queueId: string) { + return this.http.delete(`/api/tenant/queues/${queueId}`); + } } diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index 4a52fc66f6..215693f318 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -108,7 +108,7 @@ export class MenuService { name: 'admin.system-settings', type: 'toggle', path: '/settings', - height: '240px', + height: '280px', icon: 'settings', pages: [ { @@ -152,7 +152,14 @@ export class MenuService { type: 'link', path: '/settings/resources-library', icon: 'folder' - } + }, + { + id: guid(), + name: 'admin.queues', + type: 'link', + path: '/settings/queues', + icon: 'swap_calls' + }, ] } ); @@ -220,7 +227,12 @@ export class MenuService { name: 'resource.resources-library', icon: 'folder', path: '/settings/resources-library' - } + }, + { + name: 'admin.queues', + icon: 'swap_calls', + path: '/settings/queues' + }, ] } ); diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index e2eb776e5b..03ff1ff921 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -67,6 +67,36 @@
{{ 'tenant.isolated-tb-rule-engine' | translate }}
{{'tenant.isolated-tb-rule-engine-details' | translate}}
+ + tenant.max-number-of-queues + + + {{ 'tenant.max-number-of-queues-required' | translate }} + + + {{ 'tenant.max-number-of-queues-min-length' | translate }} + + + + tenant.max-number-of-partitions-per-queue + + + {{ 'tenant.max-number-of-partitions-per-queue-required' | translate }} + + + {{ 'tenant.max-number-of-partitions-per-queue-min-length' | translate }} + + { name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], + maxNumberOfQueues: [entity ? entity.maxNumberOfQueues : 1, [Validators.required, Validators.min(1)]], + maxNumberOfPartitionsPerQueue: [entity ? entity.maxNumberOfPartitionsPerQueue : 1, [Validators.required, Validators.min(1)]], profileData: [entity && !this.isAdd ? entity.profileData : { configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT) } as TenantProfileData, []], @@ -74,12 +76,26 @@ export class TenantProfileComponent extends EntityComponent { this.entityForm.patchValue({name: entity.name}); this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore}); this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}); + this.entityForm.patchValue({maxNumberOfQueues: entity.maxNumberOfQueues}); + this.entityForm.patchValue({maxNumberOfPartitionsPerQueue: entity.maxNumberOfPartitionsPerQueue}); this.entityForm.patchValue({profileData: !this.isAdd ? entity.profileData : { configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT) } as TenantProfileData}); this.entityForm.patchValue({description: entity.description}); } + showQueueParams(): boolean { + let isolatedTbRuleEngine: boolean = this.entityForm.get('isolatedTbRuleEngine').value; + if (isolatedTbRuleEngine) { + this.entityForm.controls['maxNumberOfQueues'].enable(); + this.entityForm.controls['maxNumberOfPartitionsPerQueue'].enable(); + } else { + this.entityForm.controls['maxNumberOfQueues'].disable(); + this.entityForm.controls['maxNumberOfPartitionsPerQueue'].disable(); + } + return isolatedTbRuleEngine; + } + updateFormState() { if (this.entityForm) { if (this.isEditValue) { @@ -87,6 +103,8 @@ export class TenantProfileComponent extends EntityComponent { if (!this.isAdd) { this.entityForm.get('isolatedTbCore').disable({emitEvent: false}); this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false}); + this.entityForm.get('maxNumberOfQueues').disable({emitEvent: false}); + this.entityForm.get('maxNumberOfPartitionsPerQueue').disable({emitEvent: false}); } } else { this.entityForm.disable({emitEvent: false}); diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index ddccbb4da4..3f8b26f105 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -32,6 +32,7 @@ import { ResourcesLibraryTableConfigResolver } from '@home/pages/admin/resource/ import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component'; import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages.models'; import { BreadCrumbConfig } from '@shared/components/breadcrumb'; +import { QueuesTableConfigResolver } from '@home/pages/admin/queue/queues-table-config.resolver'; @Injectable() export class OAuth2LoginProcessingUrlResolver implements Resolve { @@ -183,6 +184,22 @@ const routes: Routes = [ } } ] + }, + { + path: 'queues', + component: EntitiesTableComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.queues', + breadcrumb: { + label: 'admin.queues', + icon: 'swap_calls' + } + }, + resolve: { + entitiesTableConfig: QueuesTableConfigResolver + } } ] } @@ -193,7 +210,8 @@ const routes: Routes = [ exports: [RouterModule], providers: [ OAuth2LoginProcessingUrlResolver, - ResourcesLibraryTableConfigResolver + ResourcesLibraryTableConfigResolver, + QueuesTableConfigResolver ] }) export class AdminRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts index 326b16f950..6f5e91bd61 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts @@ -28,6 +28,7 @@ import { SmsProviderComponent } from '@home/pages/admin/sms-provider.component'; import { SendTestSmsDialogComponent } from '@home/pages/admin/send-test-sms-dialog.component'; import { HomeSettingsComponent } from '@home/pages/admin/home-settings.component'; import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources-library.component'; +import { QueueComponent} from '@home/pages/admin/queue/queue.component'; @NgModule({ declarations: @@ -39,7 +40,8 @@ import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources- SecuritySettingsComponent, OAuth2SettingsComponent, HomeSettingsComponent, - ResourcesLibraryComponent + ResourcesLibraryComponent, + QueueComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html new file mode 100644 index 0000000000..ae163d9ba7 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html @@ -0,0 +1,182 @@ + +
+ +
+ +
+
+
+ + admin.queue-name + + + {{ 'queue.name-required' | translate }} + + + + queue.poll-interval + + + {{ 'queue.poll-interval-required' | translate }} + + + {{ 'queue.poll-interval-min-value' | translate }} + + + + queue.partitions + + + {{ 'queue.partitions-required' | translate }} + + + {{ 'queue.partitions-min-value' | translate }} + + + + queue.processing-timeout + + + {{ 'queue.pack-processing-timeout-required' | translate }} + + + {{ 'queue.pack-processing-timeout-min-value' | translate }} + + + +
+ + + + + + queue.submit-strategy + {{panel1.expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }} + + +
+ + queue.submit-strategy + + + {{ strategy }} + + + + {{ 'queue.submit-strategy-type-required' | translate }} + + + + queue.batch-size + + + {{ 'queue.batch-size-required' | translate }} + + + {{ 'queue.batch-size-min-value' | translate }} + + +
+
+ + + + queue.processing-strategy + {{panel2.expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }} + + + +
+ + queue.processing-strategy + + + {{ strategy }} + + + + {{ 'queue.processing-strategy-type-required' | translate }} + + + + queue.retries + + + {{ 'queue.retries-required' | translate }} + + + {{ 'queue.retries-min-value' | translate }} + + + + queue.failure-percentage + + + {{ 'queue.failure-percentage-required' | translate }} + + + {{ 'queue.failure-percentage-min-value' | translate }} + + + {{ 'queue.failure-percentage-max-value' | translate }} + + + + queue.pause-between-retries + + + {{ 'queue.pause-between-retries-required' | translate }} + + + {{ 'queue.pause-between-retries-min-value' | translate }} + + + + queue.max-pause-between-retries + + + {{ 'queue.max-pause-between-retries-required' | translate }} + + + {{ 'queue.max-pause-between-retries-min-value' | translate }} + + +
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss new file mode 100644 index 0000000000..852e391b28 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss @@ -0,0 +1,59 @@ +/** + * 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. + */ +:host ::ng-deep { + + .mat-expansion-panel:not([class*='mat-elevation-z']) { + box-shadow: none; + } + + .mat-accordion-container { + margin-bottom: 16px; + } + + .mat-expansion-panel { + + &:hover { + box-shadow: 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 5px 5px -3px rgba(0, 0, 0, 0.2); + } + + &-header { + height: 56px; + border: 1px solid #f2f2f2; + + &-title { + align-items: center; + justify-content: space-between; + margin-right: 0; + } + } + + &.mat-expanded { + border: none; + box-shadow: 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 5px 5px -3px rgba(0, 0, 0, 0.2); + + .mat-expansion-panel { + + &-content { + margin-top: 20px; + } + + &-body { + padding-bottom: 10px; + } + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts new file mode 100644 index 0000000000..b694e21ddf --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts @@ -0,0 +1,154 @@ +/// +/// 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. +/// + +import { ChangeDetectorRef, Component, Inject } from '@angular/core'; +import { EntityType } from '@shared/models/entity-type.models'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { EntityComponent } from '@home/components/entity/entity.component'; +import { QueueInfo, QueueProcessingStrategyTypes, QueueSubmitStrategyTypes } from '@shared/models/queue.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { TranslateService } from '@ngx-translate/core'; +import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; +import set = Reflect.set; +import { distinctUntilChanged } from 'rxjs/operators'; + +@Component({ + selector: 'tb-queue', + templateUrl: './queue.component.html', + styleUrls: ['./queue.component.scss'] +}) +export class QueueComponent extends EntityComponent { + entityForm: FormGroup; + + entityType = EntityType; + submitStrategies: string[] = []; + processingStrategies: string[] = []; + + QueueSubmitStrategyTypes = QueueSubmitStrategyTypes; + hideBatchSize: boolean = false; + + constructor(protected store: Store, + protected translate: TranslateService, + @Inject('entity') protected entityValue: QueueInfo, + @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig, + protected cd: ChangeDetectorRef, + public fb: FormBuilder) { + super(store, fb, entityValue, entitiesTableConfigValue, cd); + this.submitStrategies = Object.values(QueueSubmitStrategyTypes); + this.processingStrategies = Object.values(QueueProcessingStrategyTypes); + } + + ngOnInit() { + super.ngOnInit(); + this.entityForm.get('submitStrategy').get('type').valueChanges.subscribe(() => { + this.submitStrategyTypeChanged(); + }); + } + + buildForm(entity: QueueInfo): FormGroup { + return this.fb.group( + { + name: [entity ? entity.name : '', [Validators.required]], + pollInterval: [ + entity && entity.pollInterval ? entity.pollInterval : 25, + [Validators.min(1), Validators.required] + ], + partitions: [ + entity && entity.partitions ? entity.partitions : 10, + [Validators.min(1), Validators.required] + ], + packProcessingTimeout: [ + entity && entity.packProcessingTimeout ? entity.packProcessingTimeout : 2000, + [Validators.min(1), Validators.required] + ], + submitStrategy: this.fb.group({ + type: [entity ? entity.submitStrategy?.type : null, [Validators.required]], + batchSize: [ + entity && entity.submitStrategy?.batchSize ? entity.submitStrategy?.batchSize : 1000, + [Validators.min(1), Validators.required] + ], + }), + processingStrategy: this.fb.group({ + type: [entity ? entity.processingStrategy?.type : null, [Validators.required]], + retries: [ + entity && entity.processingStrategy?.retries ? entity.processingStrategy?.retries : 3, + [Validators.min(0), Validators.required] + ], + failurePercentage: [ + entity && entity.processingStrategy?.failurePercentage ? entity.processingStrategy?.failurePercentage : 0, + [Validators.min(0), Validators.required, Validators.max(100)] + ], + pauseBetweenRetries: [ + entity && entity.processingStrategy?.pauseBetweenRetries ? entity.processingStrategy?.pauseBetweenRetries : 3, + [Validators.min(1), Validators.required] + ], + maxPauseBetweenRetries: [ + entity && entity.processingStrategy?.maxPauseBetweenRetries ? entity.processingStrategy?.maxPauseBetweenRetries : 3, + [Validators.min(1), Validators.required] + ], + }) + } + ); + } + + hideDelete() { + if (this.entitiesTableConfig) { + return !this.entitiesTableConfig.deleteEnabled(this.entity); + } else { + return false; + } + } + + updateForm(entity: QueueInfo) { + this.entityForm.patchValue({ + name: entity.name, + pollInterval: entity.pollInterval, + partitions: entity.partitions, + packProcessingTimeout: entity.packProcessingTimeout, + submitStrategy: { + type: entity.submitStrategy?.type, + batchSize: entity.submitStrategy?.batchSize, + }, + processingStrategy: { + type: entity.processingStrategy?.type, + retries: entity.processingStrategy?.retries, + failurePercentage: entity.processingStrategy?.failurePercentage, + pauseBetweenRetries: entity.processingStrategy?.pauseBetweenRetries, + maxPauseBetweenRetries: entity.processingStrategy?.maxPauseBetweenRetries, + } + }, {emitEvent: true}); + + if (!this.isAdd) { + this.entityForm.get('name').disable({emitEvent: false}); + } + } + + submitStrategyTypeChanged() { + const form = this.entityForm.get("submitStrategy") as FormGroup; + const type: QueueSubmitStrategyTypes = form.get('type').value; + const batchSizeField = form.get('batchSize'); + if (type === QueueSubmitStrategyTypes.BATCH) { + batchSizeField.enable(); + batchSizeField.patchValue(1000); + this.hideBatchSize = true; + } else { + batchSizeField.patchValue(null); + batchSizeField.disable(); + this.hideBatchSize = false; + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts new file mode 100644 index 0000000000..aaaac2168f --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts @@ -0,0 +1,115 @@ +/// +/// 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. +/// + +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; +import { + EntityTableColumn, + EntityTableConfig +} from '@home/models/entity/entities-table-config.models'; +import { QueueInfo, ServiceType } from '@shared/models/queue.models'; +import { select, Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BroadcastService } from '@core/services/broadcast.service'; +import { CustomerService } from '@core/http/customer.service'; +import { DialogService } from '@core/services/dialog.service'; +import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; +import { map, mergeMap, take } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { EntityType, entityTypeResources, entityTypeTranslations } from '@app/shared/models/entity-type.models'; +import { TranslateService } from '@ngx-translate/core'; +import { QueueComponent } from './queue.component'; +import { QueueService } from '@core/http/queue.service'; +import { selectAuthUser } from '@core/auth/auth.selectors'; + +@Injectable() +export class QueuesTableConfigResolver implements Resolve> { + + readonly queueType = ServiceType.TB_RULE_ENGINE; + + private readonly config: EntityTableConfig = new EntityTableConfig(); + + constructor(private store: Store, + private broadcast: BroadcastService, + private queueService: QueueService, + private customerService: CustomerService, + private dialogService: DialogService, + private homeDialogs: HomeDialogsService, + private translate: TranslateService) { + + this.config.entityType = EntityType.QUEUE; + this.config.entityComponent = QueueComponent; + this.config.entityTranslations = entityTypeTranslations.get(EntityType.QUEUE); + this.config.entityResources = entityTypeResources.get(EntityType.QUEUE); + + this.config.deleteEntityTitle = queue => this.translate.instant('queue.delete-queue-title', {queueName: queue.name}); + this.config.deleteEntityContent = () => this.translate.instant('queue.delete-queue-text'); + this.config.deleteEntitiesTitle = count => this.translate.instant('queue.delete-queues-title', {count}); + this.config.deleteEntitiesContent = () => this.translate.instant('queue.delete-queues-text'); + } + + resolve(route: ActivatedRouteSnapshot): Observable> { + this.config.componentsData = { + queueType: this.queueType + }; + + return this.store.pipe(select(selectAuthUser), take(1)).pipe( + map(() => { + this.config.tableTitle = this.translate.instant('admin.queues'); + this.config.columns = this.configureColumns(); + this.configureEntityFunctions(); + return this.config; + }) + ); + } + + configureColumns(): Array> { + return [ + new EntityTableColumn('name', 'admin.queue-name', '25%'), + new EntityTableColumn('partitions', 'admin.queue-partitions', '25%'), + new EntityTableColumn('submitStrategy', 'admin.queue-submit-strategy', '25%', + (entity: QueueInfo) => { + return entity.submitStrategy.type; + }, + () => ({}), + false + ), + new EntityTableColumn('processingStrategy', 'admin.queue-processing-strategy', '25%', + (entity: QueueInfo) => { + return entity.processingStrategy.type; + }, + () => ({}), + false + ) + ]; + } + + configureEntityFunctions(): void { + this.config.entitiesFetchFunction = pageLink => this.queueService.getTenantQueuesByServiceType(pageLink, this.queueType); + this.config.loadEntity = id => this.queueService.getQueueById(id.id); + this.config.saveEntity = queue => this.queueService.saveQueue(this.addTopicForQueue(queue), this.queueType).pipe( + mergeMap((savedQueue) => this.queueService.getQueueById(savedQueue.id.id) + )); + this.config.deleteEntity = id => this.queueService.deleteQueue(id.id); + this.config.deleteEnabled = (queue) => queue && queue.name !== 'Main'; + } + + private addTopicForQueue(queue: QueueInfo): QueueInfo { + const modifiedQueue = Object.assign({}, queue); + modifiedQueue.topic = `tb_rule_engine.${queue.name}`; + return modifiedQueue; + } +} diff --git a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html index e773c16743..6abd58dda9 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html +++ b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html @@ -17,7 +17,7 @@ --> {{ 'queue.name' | translate }} - - {{ 'queue.name_required' | translate }} + {{ 'queue.name-required' | translate }} device-profile.select-queue-hint diff --git a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts index 14538c9fc7..28a3d94e9e 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts +++ b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts @@ -175,7 +175,7 @@ export class QueueTypeListComponent implements ControlValueAccessor, OnInit, Aft getQueues(): Observable> { if (!this.queues) { this.queues = this.queueService. - getTenantQueuesByServiceType(this.queueType, {ignoreLoading: true}).pipe( + getTenantQueuesNamesByServiceType(this.queueType, {ignoreLoading: true}).pipe( map((queues) => { return queues.map((queueName) => { return { queueName }; diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 4bfce6414a..29f6ccc020 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -133,7 +133,8 @@ export const HelpLinks = { widgetsConfigAlarm: helpBaseUrl + '/docs/user-guide/ui/dashboards#alarm', widgetsConfigStatic: helpBaseUrl + '/docs/user-guide/ui/dashboards#static', ruleNodePushToCloud: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-cloud', - ruleNodePushToEdge: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-edge' + ruleNodePushToEdge: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-edge', + queue: helpBaseUrl + '/docs/user-guide/queue' } }; diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index 2604787b0e..9c97cdaa82 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -36,7 +36,8 @@ export enum EntityType { API_USAGE_STATE = 'API_USAGE_STATE', TB_RESOURCE = 'TB_RESOURCE', OTA_PACKAGE = 'OTA_PACKAGE', - RPC = 'RPC' + RPC = 'RPC', + QUEUE = 'QUEUE' } export enum AliasEntityType { @@ -306,6 +307,15 @@ export const entityTypeTranslations = new Map { + packProcessingTimeout: number; + partitions: number; + pollInterval: number; + processingStrategy: { + type: QueueProcessingStrategyTypes, + retries: number, + failurePercentage: number, + pauseBetweenRetries: number, + maxPauseBetweenRetries: number + }; + submitStrategy: { + type: QueueSubmitStrategyTypes, + batchSize: number, + }; + tenantId: TenantId; + topic: string; +} diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index 027c8cdce0..dc3c5200d3 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -106,6 +106,8 @@ export interface TenantProfile extends BaseData { default?: boolean; isolatedTbCore?: boolean; isolatedTbRuleEngine?: boolean; + maxNumberOfQueues?: number; + maxNumberOfPartitionsPerQueue?: number; profileData?: TenantProfileData; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index d593fd0c08..75dbdf4f5f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -252,7 +252,14 @@ "platform-ios": "iOS", "all-platforms": "All platforms", "allowed-platforms": "Allowed platforms" - } + }, + "queue-select-name": "Select queue name", + "queue-name": "Name", + "queue-name-required": "Queue name is required!", + "queues": "Queues", + "queue-partitions": "Partitions", + "queue-submit-strategy": "Submit strategy", + "queue-processing-strategy": "Processing strategy" }, "alarm": { "alarm": "Alarm", @@ -2670,10 +2677,50 @@ "browser-time": "Browser Time" }, "queue": { - "select_name": "Select queue name", - "name": "Queue Name", - "name_required": "Queue name is required!", - "no-queues-matching": "No queues matching '{{queue}}' were found." + "select-name": "Select queue name", + "name": "Name", + "name-required": "Queue name is required!", + "topic-required": "Queue topic is required!", + "poll-interval-required": "Poll interval is required!", + "poll-interval-min-value": "Poll interval value can't be less then 1", + "partitions-required": "Partitions is required!", + "partitions-min-value": "Partitions value can't be less then 1", + "pack-processing-timeout-required": "Processing timeout is required", + "pack-processing-timeout-min-value": "Processing timeout value can't be less then 1", + "batch-size-required": "Batch size is required!", + "batch-size-min-value": "Batch size value can't be less then 1", + "retries-required": "Retries is required!", + "retries-min-value": "Retries value can't be negative", + "failure-percentage-required": "Failure percentage is required!", + "failure-percentage-min-value": "Failure percentage value can't be less then 0", + "failure-percentage-max-value": "Failure percentage value can't be more then 100", + "pause-between-retries-required": "Pause between retries is required!", + "pause-between-retries-min-value": "Pause between retries value can't be less then 1", + "max-pause-between-retries-required": "Max pause between retries is required!", + "max-pause-between-retries-min-value": "Max pause between retries value can't be less then 1", + "submit-strategy-type-required": "Submit strategy type is required!", + "processing-strategy-type-required": "Processing strategy type is required!", + "queues": "Queues", + "selected-queues": "{ count, plural, 1 {1 queue} other {# queues} } selected", + "delete-queue-title": "Are you sure you want to delete the queue '{{queueName}}'?", + "delete-queues-title": "Are you sure you want to delete { count, plural, 1 {1 queue} other {# queues} }?", + "delete-queue-text": "Be careful, after the confirmation the queue and all related data will become unrecoverable.", + "delete-queues-text": "After the confirmation all selected queues will be deleted and won't be accessible.", + "search": "Search queue", + "add" : "Add queue", + "details": "Queue details", + "topic": "Topic", + "submit-strategy": "Submit Strategy", + "processing-strategy": "Processing Strategy", + "poll-interval": "Poll interval", + "partitions": "Partitions", + "processing-timeout": "Processing timeout", + "batch-size": "Batch size", + "retries": "Retries (0 - unlimited)", + "failure-percentage": "Failure Percentage", + "pause-between-retries": "Pause between retries", + "max-pause-between-retries": "Maximal pause between retries", + "delete": "Delete queue" }, "tenant": { "tenant": "Tenant", @@ -2707,7 +2754,13 @@ "isolated-tb-core": "Processing in isolated ThingsBoard Core 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", + "max-number-of-queues": "Max number of ThingsBoard Rule Engine queues", + "max-number-of-queues-required": "Max number of queues is required", + "max-number-of-queues-min-length": "Max number of queues can't be less then 1", + "max-number-of-partitions-per-queue": "Max number of partitions per ThingsBoard Rule Engine queue", + "max-number-of-partitions-per-queue-required": "Max number of partitions per queue is required", + "max-number-of-partitions-per-queue-min-length": "Max number of partitions per queue can't be less then 1" }, "tenant-profile": { "tenant-profile": "Tenant profile", From fd53d3aeb499c2d9b0c701c69d142ec95c4d2ed5 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Sun, 27 Mar 2022 23:41:30 +0300 Subject: [PATCH 02/58] added base tests for queue --- .../server/dao/tenant/TenantServiceImpl.java | 4 + .../dao/service/AbstractServiceTest.java | 4 + .../dao/service/BaseQueueServiceTest.java | 491 ++++++++++++++++++ .../dao/service/sql/QueueServiceSqlTest.java | 23 + 4 files changed, 522 insertions(+) create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/sql/QueueServiceSqlTest.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 2ae46df19a..b8d0f1f84b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -142,6 +142,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe if (tenant.getId() == null) { deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); + TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId()); + if(tenantProfile.isIsolatedTbRuleEngine()) { + queueService.createDefaultMainQueue(tenantProfile, savedTenant.getTenantId()); + } } return savedTenant; } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 34e2618ff6..dae497b52d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -57,6 +57,7 @@ import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -163,6 +164,9 @@ public abstract class AbstractServiceTest { @Autowired protected OtaPackageService otaPackageService; + @Autowired + protected QueueService queueService; + public class IdComparator implements Comparator { @Override public int compare(D o1, D o2) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java new file mode 100644 index 0000000000..29490dea04 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java @@ -0,0 +1,491 @@ +/** + * 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.dao.service; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.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.dao.exception.DataValidationException; +import org.thingsboard.server.dao.tenant.TenantServiceImpl; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class BaseQueueServiceTest extends AbstractServiceTest { + + private IdComparator idComparator = new IdComparator<>(); + + private TenantId tenantId; + private TenantProfileId tenantProfileId; + + @Before + public void before() throws NoSuchFieldException, IllegalAccessException { + Field zkEnabled = TenantServiceImpl.class.getDeclaredField("zkEnabled"); + zkEnabled.setAccessible(true); + zkEnabled.set(tenantService, Boolean.TRUE); + + 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); + tenantProfile.setMaxNumberOfQueues(10); + tenantProfile.setMaxNumberOfPartitionsPerQueue(10); + + TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); + Assert.assertNotNull(savedTenantProfile); + tenantProfileId = savedTenantProfile.getId(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + tenant.setTenantProfileId(tenantProfileId); + Tenant savedTenant = tenantService.saveTenant(tenant); + Assert.assertNotNull(savedTenant); + tenantId = savedTenant.getId(); + } + + @After + public void after() { + tenantService.deleteTenant(tenantId); + tenantProfileService.deleteTenantProfile(TenantId.SYS_TENANT_ID, tenantProfileId); + } + + private ProcessingStrategy createTestProcessingStrategy() { + ProcessingStrategy processingStrategy = new ProcessingStrategy(); + processingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES); + processingStrategy.setRetries(3); + processingStrategy.setFailurePercentage(0); + processingStrategy.setPauseBetweenRetries(3); + processingStrategy.setMaxPauseBetweenRetries(3); + return processingStrategy; + } + + private SubmitStrategy createTestSubmitStrategy() { + SubmitStrategy submitStrategy = new SubmitStrategy(); + submitStrategy.setType(SubmitStrategyType.BURST); + submitStrategy.setBatchSize(1000); + return submitStrategy; + } + + @Test + public void testSaveQueue() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + Queue savedQueue = queueService.saveQueue(queue); + + Assert.assertNotNull(savedQueue); + Assert.assertNotNull(savedQueue.getId()); + Assert.assertTrue(savedQueue.getCreatedTime() > 0); + Assert.assertEquals(queue.getTenantId(), savedQueue.getTenantId()); + Assert.assertEquals(queue.getName(), queue.getName()); + + savedQueue.setPollInterval(100); + + queueService.saveQueue(savedQueue); + Queue foundQueue = queueService.findQueueById(tenantId, savedQueue.getId()); + Assert.assertEquals(foundQueue.getPollInterval(), savedQueue.getPollInterval()); + + queueService.deleteQueue(tenantId, foundQueue.getId()); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyName() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyTopic() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyPoolInterval() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyPartitions() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyPackProcessingTimeout() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptySubmitStrategy() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyProcessingStrategy() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptySubmitStrategyType() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.getSubmitStrategy().setType(null); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptySubmitStrategyBatchSize() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.getSubmitStrategy().setType(SubmitStrategyType.BATCH); + queue.getSubmitStrategy().setBatchSize(0); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithEmptyProcessingStrategyType() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queue.getProcessingStrategy().setType(null); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithNegativeProcessingStrategyRetries() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queue.getProcessingStrategy().setRetries(-1); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithNegativeProcessingStrategyFailurePercentage() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queue.getProcessingStrategy().setFailurePercentage(-1); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithNegativeProcessingStrategyPauseBetweenRetries() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queue.getProcessingStrategy().setPauseBetweenRetries(-1); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithProcessingStrategyPauseBetweenRetriesBiggerThenMaxPauseBetweenRetries() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queue.getProcessingStrategy().setPauseBetweenRetries(100); + queueService.saveQueue(queue); + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithNotIsolatedTenant() { + Tenant tenant = new Tenant(); + tenant.setTitle("Not isolated tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + Assert.assertNotNull(savedTenant); + + Queue queue = new Queue(); + queue.setTenantId(savedTenant.getId()); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + try { + queueService.saveQueue(queue); + } finally { + tenantService.deleteTenant(savedTenant.getId()); + } + } + + @Test(expected = DataValidationException.class) + public void testSaveQueueWithExceededLimitPerTenant() { + for (int i = 1; i <= 10; i++) { + //main queue created automatically + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test" + i); + queue.setTopic("tb_rule_engine.test" + i); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + queueService.saveQueue(queue); + } + } + + @Test + public void testUpdateQueue() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + Queue savedQueue = queueService.saveQueue(queue); + + Assert.assertNotNull(savedQueue); + + queue.setPollInterval(1000); + + queueService.saveQueue(savedQueue); + + Queue foundQueue = queueService.findQueueById(tenantId, savedQueue.getId()); + + Assert.assertEquals(savedQueue, foundQueue); + } + + + @Test + public void testFindQueueById() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + Queue savedQueue = queueService.saveQueue(queue); + Queue foundQueue = queueService.findQueueById(tenantId, savedQueue.getId()); + Assert.assertNotNull(foundQueue); + Assert.assertEquals(savedQueue, foundQueue); + } + + @Test + public void testDeleteQueue() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + Queue savedQueue = queueService.saveQueue(queue); + Queue foundQueue = queueService.findQueueById(tenantId, savedQueue.getId()); + Assert.assertNotNull(foundQueue); + queueService.deleteQueue(tenantId, savedQueue.getId()); + foundQueue = queueService.findQueueById(tenantId, savedQueue.getId()); + Assert.assertNull(foundQueue); + } + + @Test + public void testFindQueueByTenantIdAndName() { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test"); + queue.setTopic("tb_rule_engine.test"); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + Queue savedQueue = queueService.saveQueue(queue); + Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, savedQueue.getName()); + + Assert.assertNotNull(foundQueue); + Assert.assertEquals(savedQueue, foundQueue); + } + + @Test + public void testFindQueuesByTenantId() { + List queues = new ArrayList<>(); + for (int i = 1; i < 10; i++) { + Queue queue = new Queue(); + queue.setTenantId(tenantId); + queue.setName("Test" + i); + queue.setTopic("tb_rule_engine.test" + i); + queue.setPollInterval(25); + queue.setPartitions(1); + queue.setPackProcessingTimeout(2000); + queue.setSubmitStrategy(createTestSubmitStrategy()); + queue.setProcessingStrategy(createTestProcessingStrategy()); + + queues.add(queueService.saveQueue(queue)); + } + + List loadedQueues = new ArrayList<>(); + PageLink pageLink = new PageLink(3); + PageData pageData = null; + do { + pageData = queueService.findQueuesByTenantId(tenantId, pageLink); + loadedQueues.addAll(pageData.getData()); + if (pageData.hasNext()) { + pageLink = pageLink.nextPageLink(); + } + } while (pageData.hasNext()); + + for (int i = 0; i < loadedQueues.size(); i++) { + Queue queue = loadedQueues.get(i); + if (queue.getName().equals("Main")) { + loadedQueues.remove(queue); + break; + } + } + + Collections.sort(queues, idComparator); + Collections.sort(loadedQueues, idComparator); + + Assert.assertEquals(queues, loadedQueues); + + queueService.deleteQueuesByTenantId(tenantId); + + pageLink = new PageLink(33); + pageData = queueService.findQueuesByTenantId(tenantId, pageLink); + Assert.assertFalse(pageData.hasNext()); + Assert.assertTrue(pageData.getData().isEmpty()); + } + +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/sql/QueueServiceSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/sql/QueueServiceSqlTest.java new file mode 100644 index 0000000000..320bb4fcaf --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/sql/QueueServiceSqlTest.java @@ -0,0 +1,23 @@ +/** + * 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.dao.service.sql; + +import org.thingsboard.server.dao.service.BaseQueueServiceTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class QueueServiceSqlTest extends BaseQueueServiceTest { +} From 3764ebfa1c59f88db38b739adb2846b3b11aa6a3 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 28 Mar 2022 22:38:31 +0300 Subject: [PATCH 03/58] implemented deleteTopic for queues --- .../server/queue/TbQueueAdmin.java | 2 +- .../common/msg/queue/TopicPartitionInfo.java | 2 +- .../queue/RuleEngineTbQueueAdminFactory.java | 114 ++++++++++++++++++ .../azure/servicebus/TbServiceBusAdmin.java | 25 ++++ .../server/queue/kafka/TbKafkaAdmin.java | 17 +++ .../InMemoryTbTransportQueueFactory.java | 3 + .../server/queue/pubsub/TbPubSubAdmin.java | 31 +++++ .../queue/rabbitmq/TbRabbitMqAdmin.java | 9 ++ .../server/queue/sqs/TbAwsSqsAdmin.java | 35 ++++-- .../server/dao/queue/BaseQueueService.java | 32 +++-- 10 files changed, 243 insertions(+), 27 deletions(-) create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/RuleEngineTbQueueAdminFactory.java diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java index 37c99dfccb..1e5873ab67 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java @@ -21,5 +21,5 @@ public interface TbQueueAdmin { void destroy(); - default void deleteTopic(String topic) { } + void deleteTopic(String topic); } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java index baf1ea0334..ae6a5146e0 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java @@ -41,7 +41,7 @@ public class TopicPartitionInfo { this.partition = partition; this.myPartition = myPartition; String tmp = topic; - if (tenantId != null) { + if (tenantId != null && !tenantId.isNullUid()) { tmp += "." + tenantId.getId().toString(); } if (partition != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/RuleEngineTbQueueAdminFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/RuleEngineTbQueueAdminFactory.java new file mode 100644 index 0000000000..1dd6c0045d --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/RuleEngineTbQueueAdminFactory.java @@ -0,0 +1,114 @@ +/** + * 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.queue; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.thingsboard.server.queue.azure.servicebus.TbServiceBusAdmin; +import org.thingsboard.server.queue.azure.servicebus.TbServiceBusQueueConfigs; +import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; +import org.thingsboard.server.queue.kafka.TbKafkaAdmin; +import org.thingsboard.server.queue.kafka.TbKafkaSettings; +import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs; +import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; +import org.thingsboard.server.queue.pubsub.TbPubSubSettings; +import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; +import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; +import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; +import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; +import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; +import org.thingsboard.server.queue.sqs.TbAwsSqsQueueAttributes; +import org.thingsboard.server.queue.sqs.TbAwsSqsSettings; + +@Configuration +public class RuleEngineTbQueueAdminFactory { + + @Autowired(required = false) + private TbKafkaTopicConfigs kafkaTopicConfigs; + @Autowired(required = false) + private TbKafkaSettings kafkaSettings; + + @Autowired(required = false) + private TbAwsSqsQueueAttributes awsSqsQueueAttributes; + @Autowired(required = false) + private TbAwsSqsSettings awsSqsSettings; + + @Autowired(required = false) + private TbPubSubSubscriptionSettings pubSubSubscriptionSettings; + @Autowired(required = false) + private TbPubSubSettings pubSubSettings; + + @Autowired(required = false) + private TbRabbitMqQueueArguments rabbitMqQueueArguments; + @Autowired(required = false) + private TbRabbitMqSettings rabbitMqSettings; + + @Autowired(required = false) + private TbServiceBusQueueConfigs serviceBusQueueConfigs; + @Autowired(required = false) + private TbServiceBusSettings serviceBusSettings; + + @ConditionalOnExpression("'${queue.type:null}'=='kafka'") + @Bean + public TbQueueAdmin createKafkaAdmin() { + return new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getRuleEngineConfigs()); + } + + @ConditionalOnExpression("'${queue.type:null}'=='aws-sqs'") + @Bean + public TbQueueAdmin createAwsSqsAdmin() { + return new TbAwsSqsAdmin(awsSqsSettings, awsSqsQueueAttributes.getRuleEngineAttributes()); + } + + @ConditionalOnExpression("'${queue.type:null}'=='pubsub'") + @Bean + public TbQueueAdmin createPubSubAdmin() { + return new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); + } + + @ConditionalOnExpression("'${queue.type:null}'=='rabbitmq'") + @Bean + public TbQueueAdmin createRabbitMqAdmin() { + return new TbRabbitMqAdmin(rabbitMqSettings, rabbitMqQueueArguments.getRuleEngineArgs()); + } + + @ConditionalOnExpression("'${queue.type:null}'=='service-bus'") + @Bean + public TbQueueAdmin createServiceBusAdmin() { + return new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); + } + + @ConditionalOnExpression("'${queue.type:null}'=='in-memory'") + @Bean + public TbQueueAdmin createInMemoryAdmin() { + return new TbQueueAdmin() { + + @Override + public void createTopicIfNotExists(String topic) { + } + + @Override + public void deleteTopic(String topic) { + } + + @Override + public void destroy() { + } + }; + } +} \ No newline at end of file diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusAdmin.java b/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusAdmin.java index 71ec4b6811..c8f76a8eeb 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusAdmin.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/azure/servicebus/TbServiceBusAdmin.java @@ -82,6 +82,31 @@ public class TbServiceBusAdmin implements TbQueueAdmin { } } + @Override + public void deleteTopic(String topic) { + if (queues.contains(topic)) { + doDelete(topic); + } else { + try { + if (client.getQueue(topic) != null) { + doDelete(topic); + } else { + log.warn("Azure Service Bus Queue [{}] is not exist.", topic); + } + } catch (ServiceBusException | InterruptedException e) { + log.error("Failed to delete Azure Service Bus queue [{}]", topic, e); + } + } + } + + private void doDelete(String topic) { + try { + client.deleteTopic(topic); + } catch (ServiceBusException | InterruptedException e) { + log.error("Failed to delete Azure Service Bus queue [{}]", topic, e); + } + } + private void setQueueConfigs(QueueDescription queueDescription) { queueConfigs.forEach((confKey, confValue) -> { switch (confKey) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaAdmin.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaAdmin.java index 1034263690..d5a9a34dc7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaAdmin.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaAdmin.java @@ -84,6 +84,23 @@ public class TbKafkaAdmin implements TbQueueAdmin { } + @Override + public void deleteTopic(String topic) { + if (topics.contains(topic)) { + client.deleteTopics(Collections.singletonList(topic)); + } else { + try { + if (client.listTopics().names().get().contains(topic)) { + client.deleteTopics(Collections.singletonList(topic)); + } else { + log.warn("Kafka topic [{}] does not exist.", topic); + } + } catch (InterruptedException | ExecutionException e) { + log.error("Failed to delete kafka topic [{}].", topic, e); + } + } + } + @Override public void destroy() { if (client != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java index cb60272ace..252b70459e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java @@ -73,6 +73,9 @@ public class InMemoryTbTransportQueueFactory implements TbTransportQueueFactory @Override public void destroy() {} + + @Override + public void deleteTopic(String topic) {} }); templateBuilder.requestTemplate(producerTemplate); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/pubsub/TbPubSubAdmin.java b/common/queue/src/main/java/org/thingsboard/server/queue/pubsub/TbPubSubAdmin.java index 7fb7cc9463..06d082feb1 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/pubsub/TbPubSubAdmin.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/pubsub/TbPubSubAdmin.java @@ -136,6 +136,37 @@ public class TbPubSubAdmin implements TbQueueAdmin { createSubscriptionIfNotExists(partition, topicName); } + @Override + public void deleteTopic(String topic) { + TopicName topicName = TopicName.newBuilder() + .setTopic(topic) + .setProject(pubSubSettings.getProjectId()) + .build(); + + ProjectSubscriptionName subscriptionName = + ProjectSubscriptionName.of(pubSubSettings.getProjectId(), topic); + + if (topicSet.contains(topicName.toString())) { + topicAdminClient.deleteTopic(topicName); + } else { + if (topicAdminClient.getTopic(topicName) != null) { + topicAdminClient.deleteTopic(topicName); + } else { + log.warn("PubSub topic [{}] does not exist.", topic); + } + } + + if (subscriptionSet.contains(subscriptionName.toString())) { + subscriptionAdminClient.deleteSubscription(subscriptionName); + } else { + if (subscriptionAdminClient.getSubscription(subscriptionName) != null) { + subscriptionAdminClient.deleteSubscription(subscriptionName); + } else { + log.warn("PubSub subscription [{}] does not exist.", topic); + } + } + } + private void createSubscriptionIfNotExists(String partition, TopicName topicName) { ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(pubSubSettings.getProjectId(), partition); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqAdmin.java b/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqAdmin.java index d2e5172a6f..3c7c18ad93 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqAdmin.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqAdmin.java @@ -58,6 +58,15 @@ public class TbRabbitMqAdmin implements TbQueueAdmin { } } + @Override + public void deleteTopic(String topic) { + try { + channel.queueDelete(topic); + } catch (IOException e) { + log.error("Failed to delete RabbitMq queue [{}].", topic); + } + } + @Override public void destroy() { if (channel != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/sqs/TbAwsSqsAdmin.java b/common/queue/src/main/java/org/thingsboard/server/queue/sqs/TbAwsSqsAdmin.java index 39ffc65e4a..3bd141f4db 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/sqs/TbAwsSqsAdmin.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/sqs/TbAwsSqsAdmin.java @@ -23,18 +23,20 @@ import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.AmazonSQSClientBuilder; import com.amazonaws.services.sqs.model.CreateQueueRequest; +import com.amazonaws.services.sqs.model.GetQueueUrlResult; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.queue.TbQueueAdmin; import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.stream.Collectors; +@Slf4j public class TbAwsSqsAdmin implements TbQueueAdmin { private final Map attributes; private final AmazonSQS sqsClient; - private final Set queues; + private final Map queues; public TbAwsSqsAdmin(TbAwsSqsSettings sqsSettings, Map attributes) { this.attributes = attributes; @@ -57,18 +59,37 @@ public class TbAwsSqsAdmin implements TbQueueAdmin { .getQueueUrls() .stream() .map(this::getQueueNameFromUrl) - .collect(Collectors.toCollection(ConcurrentHashMap::newKeySet)); + .collect(Collectors.toMap(this::convertTopicToQueueName, Function.identity())); } @Override public void createTopicIfNotExists(String topic) { - String queueName = topic.replaceAll("\\.", "_") + ".fifo"; - if (queues.contains(queueName)) { + String queueName = convertTopicToQueueName(topic); + if (queues.containsKey(queueName)) { return; } final CreateQueueRequest createQueueRequest = new CreateQueueRequest(queueName).withAttributes(attributes); String queueUrl = sqsClient.createQueue(createQueueRequest).getQueueUrl(); - queues.add(getQueueNameFromUrl(queueUrl)); + queues.put(getQueueNameFromUrl(queueUrl), queueUrl); + } + + private String convertTopicToQueueName(String topic) { + return topic.replaceAll("\\.", "_") + ".fifo"; + } + + @Override + public void deleteTopic(String topic) { + String queueName = convertTopicToQueueName(topic); + if (queues.containsKey(queueName)) { + sqsClient.deleteQueue(queues.get(queueName)); + } else { + GetQueueUrlResult queueUrl = sqsClient.getQueueUrl(queueName); + if (queueUrl != null) { + sqsClient.deleteQueue(queueUrl.getQueueUrl()); + } else { + log.warn("Aws SQS queue [{}] does not exist!", queueName); + } + } } private String getQueueNameFromUrl(String queueUrl) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index cad7f9cb48..75978ea371 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -38,7 +38,6 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.queue.TbQueueAdmin; import java.util.List; @@ -51,9 +50,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ @Autowired private QueueDao queueDao; - @Autowired - private TenantDao tenantDao; - @Autowired private TbTenantProfileCache tenantProfileCache; @@ -101,21 +97,21 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ int oldPartitions = oldQueue.getPartitions(); int currentPartitions = queue.getPartitions(); - //TODO: 3.2 remove if partitions can't be deleted. -// if (currentPartitions != oldPartitions && tbQueueAdmin != null) { + //TODO: remove if partitions can't be deleted. + if (currentPartitions != oldPartitions && tbQueueAdmin != null) { // queueClusterService.onQueueDelete(queue, null); -// if (currentPartitions > oldPartitions) { -// log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); -// for (int i = oldPartitions; i < currentPartitions; i++) { -// tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); -// } -// } else { -// log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); -// for (int i = currentPartitions; i < oldPartitions; i++) { -// tbQueueAdmin.deleteTopic(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); -// } -// } -// } + if (currentPartitions > oldPartitions) { + log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); + for (int i = oldPartitions; i < currentPartitions; i++) { + tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + } + } else { + log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); + for (int i = currentPartitions; i < oldPartitions; i++) { + tbQueueAdmin.deleteTopic(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + } + } + } return updatedQueue; } From e5eb484c2f6c0309e5a3e0f0fa8b0d466bbf1607 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 29 Mar 2022 21:42:46 +0300 Subject: [PATCH 04/58] added TbQueueClusterService and NorificationsTopicService --- .../queue/DefaultTbClusterService.java | 115 ++++++++++++++++-- .../DefaultSubscriptionManagerService.java | 22 ++-- .../DefaultTbCoreToTransportService.java | 13 +- .../server/cluster/TbClusterService.java | 10 +- .../server/queue/TbQueueClusterService.java | 24 ++++ .../queue/discovery/HashPartitionService.java | 14 --- .../discovery/NotificationsTopicService.java | 54 ++++++++ .../queue/discovery/PartitionService.java | 9 -- .../provider/AwsSqsMonolithQueueFactory.java | 22 ++-- .../provider/AwsSqsTbCoreQueueFactory.java | 10 +- .../AwsSqsTbRuleEngineQueueFactory.java | 10 +- .../InMemoryMonolithQueueFactory.java | 12 +- .../provider/KafkaMonolithQueueFactory.java | 12 +- .../provider/KafkaTbCoreQueueFactory.java | 11 +- .../KafkaTbRuleEngineQueueFactory.java | 10 +- .../provider/PubSubMonolithQueueFactory.java | 12 +- .../provider/PubSubTbCoreQueueFactory.java | 10 +- .../PubSubTbRuleEngineQueueFactory.java | 10 +- .../RabbitMqMonolithQueueFactory.java | 12 +- .../provider/RabbitMqTbCoreQueueFactory.java | 10 +- .../RabbitMqTbRuleEngineQueueFactory.java | 10 +- .../ServiceBusMonolithQueueFactory.java | 12 +- .../ServiceBusTbCoreQueueFactory.java | 10 +- .../ServiceBusTbRuleEngineQueueFactory.java | 10 +- .../service/DefaultTransportService.java | 6 +- .../server/dao/queue/BaseQueueService.java | 13 +- 26 files changed, 316 insertions(+), 147 deletions(-) create mode 100644 common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/discovery/NotificationsTopicService.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 4344507dd9..ebe99d99e0 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -18,7 +18,9 @@ package org.thingsboard.server.service.queue; import com.google.protobuf.ByteString; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; @@ -27,6 +29,7 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.Device; @@ -60,6 +63,7 @@ import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.MultipleTbQueueCallbackWrapper; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; @@ -88,8 +92,12 @@ public class DefaultTbClusterService implements TbClusterService { private final AtomicInteger toRuleEngineNfs = new AtomicInteger(0); private final AtomicInteger toTransportNfs = new AtomicInteger(0); + @Autowired + @Lazy + private PartitionService partitionService; + private final TbQueueProducerProvider producerProvider; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final DataDecodingEncodingService encodingService; private final TbDeviceProfileCache deviceProfileCache; private final OtaPackageStateService otaPackageStateService; @@ -120,7 +128,7 @@ public class DefaultTbClusterService implements TbClusterService { @Override public void pushNotificationToCore(String serviceId, FromDeviceRpcResponse response, TbQueueCallback callback) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); log.trace("PUSHING msg: {} to:{}", response, tpi); FromDeviceRPCResponseProto.Builder builder = FromDeviceRPCResponseProto.newBuilder() .setRequestIdMSB(response.getId().getMostSignificantBits()) @@ -185,7 +193,7 @@ public class DefaultTbClusterService implements TbClusterService { @Override public void pushNotificationToRuleEngine(String serviceId, FromDeviceRpcResponse response, TbQueueCallback callback) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceId); log.trace("PUSHING msg: {} to:{}", response, tpi); FromDeviceRPCResponseProto.Builder builder = FromDeviceRPCResponseProto.newBuilder() .setRequestIdMSB(response.getId().getMostSignificantBits()) @@ -199,14 +207,14 @@ public class DefaultTbClusterService implements TbClusterService { @Override public void pushNotificationToTransport(String serviceId, ToTransportMsg response, TbQueueCallback callback) { - if (serviceId == null || serviceId.isEmpty()){ + if (serviceId == null || serviceId.isEmpty()) { log.trace("pushNotificationToTransport: skipping message without serviceId [{}], (ToTransportMsg) response [{}]", serviceId, response); if (callback != null) { callback.onSuccess(null); //callback that message already sent, no useful payload expected } return; } - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceId); log.trace("PUSHING msg: {} to:{}", response, tpi); producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), response), callback); toTransportNfs.incrementAndGet(); @@ -314,7 +322,7 @@ public class DefaultTbClusterService implements TbClusterService { Set tbTransportServices = partitionService.getAllServiceIds(ServiceType.TB_TRANSPORT); TbQueueCallback proxyCallback = callback != null ? new MultipleTbQueueCallbackWrapper(tbTransportServices.size(), callback) : null; for (String transportServiceId : tbTransportServices) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportServiceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportServiceId); toTransportNfProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), proxyCallback); toTransportNfs.incrementAndGet(); } @@ -328,7 +336,7 @@ public class DefaultTbClusterService implements TbClusterService { TbQueueProducer> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer(); Set tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE); for (String serviceId : tbCoreServices) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setEdgeEventUpdateMsg(ByteString.copyFrom(msgBytes)).build(); toCoreNfProducer.send(tpi, new TbProtoQueueMsg<>(msg.getEdgeId().getId(), toCoreMsg), null); toCoreNfs.incrementAndGet(); @@ -349,7 +357,7 @@ public class DefaultTbClusterService implements TbClusterService { TbQueueProducer> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer(); Set tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE); for (String serviceId : tbCoreServices) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setComponentLifecycleMsg(ByteString.copyFrom(msgBytes)).build(); toCoreNfProducer.send(tpi, new TbProtoQueueMsg<>(msg.getEntityId().getId(), toCoreMsg), null); toCoreNfs.incrementAndGet(); @@ -358,7 +366,7 @@ public class DefaultTbClusterService implements TbClusterService { tbRuleEngineServices.removeAll(tbCoreServices); } for (String serviceId : tbRuleEngineServices) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceId); ToRuleEngineNotificationMsg toRuleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setComponentLifecycleMsg(ByteString.copyFrom(msgBytes)).build(); toRuleEngineProducer.send(tpi, new TbProtoQueueMsg<>(msg.getEntityId().getId(), toRuleEngineMsg), null); toRuleEngineNfs.incrementAndGet(); @@ -473,4 +481,93 @@ public class DefaultTbClusterService implements TbClusterService { break; } } + + @Override + public void onQueueChange(Queue queue, TbQueueCallback callback) { + log.trace("[{}][{}] Processing queue change [{}] event", queue.getTenantId(), queue.getId(), queue.getName()); + +// TransportProtos.QueueUpdateMsg queueUpdateMsg = TransportProtos.QueueUpdateMsg.newBuilder() +// .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) +// .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) +// .setQueueName(queue.getName()) +// .setQueueTopic(queue.getTopic()) +// .setPartitions(queue.getPartitions()) +// .build(); +// +// if ("Main".equals(queue.getName())) { +// Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); +// ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); +// for (TransportProtos.ServiceInfo transportService : tbTransportServices) { +// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); +// producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); +// toTransportNfs.incrementAndGet(); +// } +// +// Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); +// ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); +// for (TransportProtos.ServiceInfo coreService : tbCoreServices) { +// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); +// producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); +// toCoreNfs.incrementAndGet(); +// } +// } else { +// Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); +// ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); +// for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { +// TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); +// if (tenantId.equals(queue.getTenantId())) { +// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); +// producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); +// toRuleEngineNfs.incrementAndGet(); +// } +// } +// } + } + + @Override + public void onQueueDelete(Queue queue, TbQueueCallback callback) { + log.trace("[{}][{}] Processing queue delete [{}] event", queue.getTenantId(), queue.getId(), queue.getName()); + +// TransportProtos.QueueDeleteMsg queueDeleteMsg = TransportProtos.QueueDeleteMsg.newBuilder() +// .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) +// .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) +// .setQueueName(queue.getName()) +// .build(); +// +// if ("Main".equals(queue.getName())) { +// Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); +// ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); +// for (TransportProtos.ServiceInfo transportService : tbTransportServices) { +// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); +// producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); +// toTransportNfs.incrementAndGet(); +// } +// +// Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); +// ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); +// for (TransportProtos.ServiceInfo coreService : tbCoreServices) { +// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); +// producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); +// toCoreNfs.incrementAndGet(); +// } +// } else { +// //TODO: 3.2 should be changed with smth like TransportApiRequestTemplate and get responses from all RE's +// Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); +// ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); +// for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { +// TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); +// if (tenantId.equals(queue.getTenantId())) { +// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); +// log.info("Send notification about deleting queue [{}] to Rule Engine [{}]", queue.getName(), tpi.getFullTopicName()); +// producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); +// toRuleEngineNfs.incrementAndGet(); +// } +// } +// try { +// Thread.sleep(3000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } + } } diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 83398e29ed..b158a51b77 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -50,6 +50,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdate import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.TbApplicationEventListener; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; @@ -88,6 +89,9 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene @Autowired private TimeseriesService tsService; + @Autowired + private NotificationsTopicService notificationsTopicService; + @Autowired private PartitionService partitionService; @@ -264,7 +268,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene updateDeviceInactivityTimeout(tenantId, entityId, attributes); } else if (TbAttributeSubscriptionScope.SHARED_SCOPE.name().equalsIgnoreCase(scope) && notifyDevice) { clusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onUpdate(tenantId, - new DeviceId(entityId.getId()), DataConstants.SHARED_SCOPE, new ArrayList<>(attributes)) + new DeviceId(entityId.getId()), DataConstants.SHARED_SCOPE, new ArrayList<>(attributes)) , null); } } @@ -377,7 +381,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene TelemetrySubscriptionUpdate update = new TelemetrySubscriptionUpdate(s.getSubscriptionId(), subscriptionUpdate); localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY); } else { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); toCoreNotificationsProducer.send(tpi, toProto(s, subscriptionUpdate, ignoreEmptyUpdates), null); } } @@ -400,7 +404,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene AlarmSubscriptionUpdate update = new AlarmSubscriptionUpdate(s.getSubscriptionId(), alarm, deleted); localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY); } else { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); toCoreNotificationsProducer.send(tpi, toProto(s, alarm, deleted), null); } } @@ -441,7 +445,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene } }); if (!missedUpdates.isEmpty()) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId()); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId()); toCoreNotificationsProducer.send(tpi, toProto(subscription, missedUpdates), null); } }, @@ -464,7 +468,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene DonAsynchron.withCallback(tsService.findLatest(subscription.getTenantId(), subscription.getEntityId(), subscription.getKeyStates().keySet()), missedUpdates -> { if (missedUpdates != null && !missedUpdates.isEmpty()) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId()); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId()); toCoreNotificationsProducer.send(tpi, toProto(subscription, missedUpdates), null); } }, @@ -483,7 +487,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene DonAsynchron.withCallback(tsService.findAll(subscription.getTenantId(), subscription.getEntityId(), queries), missedUpdates -> { if (missedUpdates != null && !missedUpdates.isEmpty()) { - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId()); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId()); toCoreNotificationsProducer.send(tpi, toProto(subscription, missedUpdates), null); } }, @@ -533,7 +537,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene }); ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg( - LocalSubscriptionServiceMsgProto.newBuilder().setSubUpdate(builder.build()).build()) + LocalSubscriptionServiceMsgProto.newBuilder().setSubUpdate(builder.build()).build()) .build(); return new TbProtoQueueMsg<>(subscription.getEntityId().getId(), toCoreMsg); } @@ -547,8 +551,8 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene builder.setDeleted(deleted); ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg( - LocalSubscriptionServiceMsgProto.newBuilder() - .setAlarmSubUpdate(builder.build()).build()) + LocalSubscriptionServiceMsgProto.newBuilder() + .setAlarmSubUpdate(builder.build()).build()) .build(); return new TbProtoQueueMsg<>(subscription.getEntityId().getId(), toCoreMsg); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTbCoreToTransportService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTbCoreToTransportService.java index 883cfd645c..0228743076 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTbCoreToTransportService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTbCoreToTransportService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.transport; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -25,7 +24,7 @@ import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -39,11 +38,11 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @TbCoreComponent public class DefaultTbCoreToTransportService implements TbCoreToTransportService { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueProducer> tbTransportProducer; - public DefaultTbCoreToTransportService(PartitionService partitionService, TbQueueProducerProvider tbQueueProducerProvider) { - this.partitionService = partitionService; + public DefaultTbCoreToTransportService(NotificationsTopicService notificationsTopicService, TbQueueProducerProvider tbQueueProducerProvider) { + this.notificationsTopicService = notificationsTopicService; this.tbTransportProducer = tbQueueProducerProvider.getTransportNotificationsMsgProducer(); } @@ -54,14 +53,14 @@ public class DefaultTbCoreToTransportService implements TbCoreToTransportService @Override public void process(String nodeId, ToTransportMsg msg, Runnable onSuccess, Consumer onFailure) { - if (nodeId == null || nodeId.isEmpty()){ + if (nodeId == null || nodeId.isEmpty()) { log.trace("process: skipping message without nodeId [{}], (ToTransportMsg) msg [{}]", nodeId, msg); if (onSuccess != null) { onSuccess.run(); } return; } - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, nodeId); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, nodeId); UUID sessionId = new UUID(msg.getSessionIdMSB(), msg.getSessionIdLSB()); log.trace("[{}][{}] Pushing session data to topic: {}", tpi.getFullTopicName(), sessionId, msg); TbProtoQueueMsg queueMsg = new TbProtoQueueMsg<>(NULL_UUID, msg); diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java index 7fb3a83425..22953f259a 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java @@ -15,31 +15,31 @@ */ package org.thingsboard.server.cluster; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; -import org.thingsboard.server.common.data.edge.EdgeEventType; -import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.queue.TbQueueCallback; +import org.thingsboard.server.queue.TbQueueClusterService; import java.util.UUID; -public interface TbClusterService { +public interface TbClusterService extends TbQueueClusterService { void pushMsgToCore(TopicPartitionInfo tpi, UUID msgKey, ToCoreMsg msg, TbQueueCallback callback); diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java new file mode 100644 index 0000000000..d37760211f --- /dev/null +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java @@ -0,0 +1,24 @@ +/** + * 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.queue; + +import org.thingsboard.server.common.data.queue.Queue; + +public interface TbQueueClusterService { + void onQueueChange(Queue queue, TbQueueCallback callback); + + void onQueueDelete(Queue queue, TbQueueCallback callback); +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 4882a96f72..96df34186c 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -213,20 +213,6 @@ public class HashPartitionService implements PartitionService { return result; } - @Override - public TopicPartitionInfo getNotificationsTopic(ServiceType serviceType, String serviceId) { - switch (serviceType) { - case TB_CORE: - return tbCoreNotificationTopics.computeIfAbsent(serviceId, - id -> buildNotificationsTopicPartitionInfo(serviceType, serviceId)); - case TB_RULE_ENGINE: - return tbRuleEngineNotificationTopics.computeIfAbsent(serviceId, - id -> buildNotificationsTopicPartitionInfo(serviceType, serviceId)); - default: - return buildNotificationsTopicPartitionInfo(serviceType, serviceId); - } - } - @Override public int resolvePartitionIndex(UUID entityId, int partitions) { int hash = hashFunction.newHasher() diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/NotificationsTopicService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/NotificationsTopicService.java new file mode 100644 index 0000000000..2c259a3ce0 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/NotificationsTopicService.java @@ -0,0 +1,54 @@ +/** + * 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.queue.discovery; + +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class NotificationsTopicService { + + private Map tbCoreNotificationTopics = new HashMap<>(); + private Map tbRuleEngineNotificationTopics = new HashMap<>(); + + /** + * Each Service should start a consumer for messages that target individual service instance based on serviceId. + * This topic is likely to have single partition, and is always assigned to the service. + * @param serviceType + * @param serviceId + * @return + */ + public TopicPartitionInfo getNotificationsTopic(ServiceType serviceType, String serviceId) { + switch (serviceType) { + case TB_CORE: + return tbCoreNotificationTopics.computeIfAbsent(serviceId, + id -> buildNotificationsTopicPartitionInfo(serviceType, serviceId)); + case TB_RULE_ENGINE: + return tbRuleEngineNotificationTopics.computeIfAbsent(serviceId, + id -> buildNotificationsTopicPartitionInfo(serviceType, serviceId)); + default: + return buildNotificationsTopicPartitionInfo(serviceType, serviceId); + } + } + + private TopicPartitionInfo buildNotificationsTopicPartitionInfo(ServiceType serviceType, String serviceId) { + return new TopicPartitionInfo(serviceType.name().toLowerCase() + ".notifications." + serviceId, null, null, false); + } +} \ No newline at end of file diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java index c011e6545a..c222b252a5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java @@ -49,15 +49,6 @@ public interface PartitionService { */ Set getAllServiceIds(ServiceType serviceType); - /** - * Each Service should start a consumer for messages that target individual service instance based on serviceId. - * This topic is likely to have single partition, and is always assigned to the service. - * @param serviceType - * @param serviceId - * @return - */ - TopicPartitionInfo getNotificationsTopic(ServiceType serviceType, String serviceId); - int resolvePartitionIndex(UUID entityId, int partitions); int countTransportsByType(String type); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java index 9979e03608..873719c832 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java @@ -22,7 +22,15 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; -import org.thingsboard.server.gen.transport.TransportProtos.*; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -30,7 +38,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; @@ -51,7 +59,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='monolith'") public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -66,7 +74,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; - public AwsSqsMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public AwsSqsMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueTransportApiSettings transportApiSettings, @@ -74,7 +82,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng TbAwsSqsSettings sqsSettings, TbAwsSqsQueueAttributes sqsQueueAttributes, TbQueueRemoteJsInvokeSettings jsInvokeSettings) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -124,7 +132,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } @@ -137,7 +145,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java index a09e832892..81736c2b55 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java @@ -37,7 +37,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; @@ -61,7 +61,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueCoreSettings coreSettings; private final TbQueueTransportApiSettings transportApiSettings; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; @@ -76,7 +76,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { TbQueueCoreSettings coreSettings, TbQueueTransportApiSettings transportApiSettings, TbQueueRuleEngineSettings ruleEngineSettings, - PartitionService partitionService, + NotificationsTopicService notificationsTopicService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbAwsSqsQueueAttributes sqsQueueAttributes, @@ -85,7 +85,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { this.coreSettings = coreSettings; this.transportApiSettings = transportApiSettings; this.ruleEngineSettings = ruleEngineSettings; - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; this.transportNotificationSettings = transportNotificationSettings; @@ -131,7 +131,7 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java index ac4898e48d..9c223f08f5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java @@ -32,7 +32,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; @@ -52,7 +52,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='tb-rule-engine'") public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -65,14 +65,14 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory private final TbQueueAdmin jsExecutorAdmin; private final TbQueueAdmin notificationAdmin; - public AwsSqsTbRuleEngineQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public AwsSqsTbRuleEngineQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbAwsSqsSettings sqsSettings, TbAwsSqsQueueAttributes sqsQueueAttributes, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -120,7 +120,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index 0548603cb7..e3c81df1dd 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -27,7 +27,7 @@ import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.memory.InMemoryStorage; import org.thingsboard.server.queue.memory.InMemoryTbQueueConsumer; @@ -43,7 +43,7 @@ import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; @ConditionalOnExpression("'${queue.type:null}'=='in-memory' && '${service.type:null}'=='monolith'") public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -51,12 +51,12 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE private final TbQueueTransportNotificationSettings transportNotificationSettings; private final InMemoryStorage storage; - public InMemoryMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public InMemoryMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueTransportApiSettings transportApiSettings, TbQueueTransportNotificationSettings transportNotificationSettings) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -97,7 +97,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { - return new InMemoryTbQueueConsumer<>(partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName()); + return new InMemoryTbQueueConsumer<>(notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName()); } @Override @@ -107,7 +107,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { - return new InMemoryTbQueueConsumer<>(partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); + return new InMemoryTbQueueConsumer<>(notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index cf75a77135..ce171497de 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -37,7 +37,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.kafka.TbKafkaAdmin; import org.thingsboard.server.queue.kafka.TbKafkaConsumerStatsService; @@ -60,7 +60,7 @@ import java.util.concurrent.atomic.AtomicLong; @ConditionalOnExpression("'${queue.type:null}'=='kafka' && '${service.type:null}'=='monolith'") public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbKafkaSettings kafkaSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueCoreSettings coreSettings; @@ -78,7 +78,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi private final TbQueueAdmin fwUpdatesAdmin; private final AtomicLong consumerCount = new AtomicLong(); - public KafkaMonolithQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, + public KafkaMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbKafkaSettings kafkaSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, @@ -87,7 +87,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbKafkaConsumerStatsService consumerStatsService, TbKafkaTopicConfigs kafkaTopicConfigs) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.kafkaSettings = kafkaSettings; this.serviceInfoProvider = serviceInfoProvider; this.coreSettings = coreSettings; @@ -173,7 +173,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); - consumerBuilder.topic(partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName()); + consumerBuilder.topic(notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName()); consumerBuilder.clientId("monolith-rule-engine-notifications-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId("monolith-rule-engine-notifications-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); @@ -199,7 +199,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); - consumerBuilder.topic(partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); + consumerBuilder.topic(notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); consumerBuilder.clientId("monolith-core-notifications-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId("monolith-core-notifications-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java index 4f12f797f0..58dec0792a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java @@ -37,7 +37,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.kafka.TbKafkaAdmin; import org.thingsboard.server.queue.kafka.TbKafkaConsumerStatsService; @@ -58,7 +58,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='kafka' && '${service.type:null}'=='tb-core'") public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbKafkaSettings kafkaSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueCoreSettings coreSettings; @@ -75,7 +75,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueAdmin notificationAdmin; private final TbQueueAdmin fwUpdatesAdmin; - public KafkaTbCoreQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, + public KafkaTbCoreQueueFactory(NotificationsTopicService notificationsTopicService, + TbKafkaSettings kafkaSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, @@ -84,7 +85,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { TbKafkaConsumerStatsService consumerStatsService, TbQueueTransportNotificationSettings transportNotificationSettings, TbKafkaTopicConfigs kafkaTopicConfigs) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.kafkaSettings = kafkaSettings; this.serviceInfoProvider = serviceInfoProvider; this.coreSettings = coreSettings; @@ -169,7 +170,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); - consumerBuilder.topic(partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); + consumerBuilder.topic(notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); consumerBuilder.clientId("tb-core-notifications-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId("tb-core-notifications-node-" + serviceInfoProvider.getServiceId()); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java index 2ed638ac35..645cbee906 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java @@ -35,7 +35,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.kafka.TbKafkaAdmin; import org.thingsboard.server.queue.kafka.TbKafkaConsumerStatsService; @@ -57,7 +57,7 @@ import java.util.concurrent.atomic.AtomicLong; @ConditionalOnExpression("'${queue.type:null}'=='kafka' && '${service.type:null}'=='tb-rule-engine'") public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbKafkaSettings kafkaSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueCoreSettings coreSettings; @@ -73,7 +73,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { private final TbQueueAdmin fwUpdatesAdmin; private final AtomicLong consumerCount = new AtomicLong(); - public KafkaTbRuleEngineQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, + public KafkaTbRuleEngineQueueFactory(NotificationsTopicService notificationsTopicService, TbKafkaSettings kafkaSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, @@ -81,7 +81,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { TbKafkaConsumerStatsService consumerStatsService, TbQueueTransportNotificationSettings transportNotificationSettings, TbKafkaTopicConfigs kafkaTopicConfigs) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.kafkaSettings = kafkaSettings; this.serviceInfoProvider = serviceInfoProvider; this.coreSettings = coreSettings; @@ -175,7 +175,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); - consumerBuilder.topic(partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName()); + consumerBuilder.topic(notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName()); consumerBuilder.clientId("tb-rule-engine-notifications-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId("tb-rule-engine-notifications-node-" + serviceInfoProvider.getServiceId()); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java index 3b31531583..3388f0d0f3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java @@ -38,7 +38,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; @@ -64,7 +64,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueTransportApiSettings transportApiSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; @@ -79,7 +79,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng TbQueueRuleEngineSettings ruleEngineSettings, TbQueueTransportApiSettings transportApiSettings, TbQueueTransportNotificationSettings transportNotificationSettings, - PartitionService partitionService, + NotificationsTopicService notificationsTopicService, TbServiceInfoProvider serviceInfoProvider, TbPubSubSubscriptionSettings pubSubSubscriptionSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings) { @@ -88,7 +88,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng this.ruleEngineSettings = ruleEngineSettings; this.transportApiSettings = transportApiSettings; this.transportNotificationSettings = transportNotificationSettings; - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.serviceInfoProvider = serviceInfoProvider; this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); @@ -134,7 +134,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } @@ -147,7 +147,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java index 3b1c3c81c9..18a6668581 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java @@ -37,7 +37,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; @@ -60,7 +60,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { private final TbPubSubSettings pubSubSettings; private final TbQueueCoreSettings coreSettings; private final TbQueueTransportApiSettings transportApiSettings; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; @@ -75,7 +75,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { public PubSubTbCoreQueueFactory(TbPubSubSettings pubSubSettings, TbQueueCoreSettings coreSettings, TbQueueTransportApiSettings transportApiSettings, - PartitionService partitionService, + NotificationsTopicService notificationsTopicService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings, @@ -84,7 +84,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { this.pubSubSettings = pubSubSettings; this.coreSettings = coreSettings; this.transportApiSettings = transportApiSettings; - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; this.transportNotificationSettings = transportNotificationSettings; @@ -131,7 +131,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java index d5acbeb4c8..8a3b88846f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java @@ -35,7 +35,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; @@ -58,7 +58,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory private final TbPubSubSettings pubSubSettings; private final TbQueueCoreSettings coreSettings; private final TbQueueRuleEngineSettings ruleEngineSettings; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; @@ -71,7 +71,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory public PubSubTbRuleEngineQueueFactory(TbPubSubSettings pubSubSettings, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, - PartitionService partitionService, + NotificationsTopicService notificationsTopicService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings, @@ -79,7 +79,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory this.pubSubSettings = pubSubSettings; this.coreSettings = coreSettings; this.ruleEngineSettings = ruleEngineSettings; - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; this.transportNotificationSettings = transportNotificationSettings; @@ -124,7 +124,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java index 80ae1d24a9..a22f6811e3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java @@ -38,7 +38,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; @@ -59,7 +59,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && '${service.type:null}'=='monolith'") public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -74,7 +74,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; - public RabbitMqMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public RabbitMqMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueTransportApiSettings transportApiSettings, @@ -82,7 +82,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE TbRabbitMqSettings rabbitMqSettings, TbRabbitMqQueueArguments queueArguments, TbQueueRemoteJsInvokeSettings jsInvokeSettings) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -132,7 +132,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } @@ -145,7 +145,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java index e2abcde93c..e728be6085 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java @@ -37,7 +37,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; @@ -61,7 +61,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueCoreSettings coreSettings; private final TbQueueTransportApiSettings transportApiSettings; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; @@ -76,7 +76,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { TbQueueCoreSettings coreSettings, TbQueueTransportApiSettings transportApiSettings, TbQueueRuleEngineSettings ruleEngineSettings, - PartitionService partitionService, + NotificationsTopicService notificationsTopicService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings, @@ -85,7 +85,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { this.coreSettings = coreSettings; this.transportApiSettings = transportApiSettings; this.ruleEngineSettings = ruleEngineSettings; - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; this.transportNotificationSettings = transportNotificationSettings; @@ -131,7 +131,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java index c17ce6a058..21e152787d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java @@ -35,7 +35,7 @@ import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; @@ -55,7 +55,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && '${service.type:null}'=='tb-rule-engine'") public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -68,14 +68,14 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor private final TbQueueAdmin jsExecutorAdmin; private final TbQueueAdmin notificationAdmin; - public RabbitMqTbRuleEngineQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public RabbitMqTbRuleEngineQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbRabbitMqSettings rabbitMqSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings, TbRabbitMqQueueArguments queueArguments) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -123,7 +123,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java index 86dafd18d3..da219d9084 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java @@ -42,7 +42,7 @@ import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; @@ -58,7 +58,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='service-bus' && '${service.type:null}'=='monolith'") public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -73,7 +73,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; - public ServiceBusMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public ServiceBusMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueTransportApiSettings transportApiSettings, @@ -81,7 +81,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul TbServiceBusSettings serviceBusSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbServiceBusQueueConfigs serviceBusQueueConfigs) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -131,7 +131,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } @@ -144,7 +144,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java index 815f4c8b38..e1eb41b2b2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java @@ -42,7 +42,7 @@ import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; @@ -61,7 +61,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueCoreSettings coreSettings; private final TbQueueTransportApiSettings transportApiSettings; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; @@ -76,7 +76,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { TbQueueCoreSettings coreSettings, TbQueueTransportApiSettings transportApiSettings, TbQueueRuleEngineSettings ruleEngineSettings, - PartitionService partitionService, + NotificationsTopicService notificationsTopicService, TbServiceInfoProvider serviceInfoProvider, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings, @@ -85,7 +85,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { this.coreSettings = coreSettings; this.transportApiSettings = transportApiSettings; this.ruleEngineSettings = ruleEngineSettings; - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.serviceInfoProvider = serviceInfoProvider; this.jsInvokeSettings = jsInvokeSettings; this.transportNotificationSettings = transportNotificationSettings; @@ -131,7 +131,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { @Override public TbQueueConsumer> createToCoreNotificationsMsgConsumer() { return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, - partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java index daa6db1a6e..a6ef991f57 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java @@ -40,7 +40,7 @@ import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; @@ -55,7 +55,7 @@ import java.nio.charset.StandardCharsets; @ConditionalOnExpression("'${queue.type:null}'=='service-bus' && '${service.type:null}'=='tb-rule-engine'") public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; @@ -68,14 +68,14 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact private final TbQueueAdmin jsExecutorAdmin; private final TbQueueAdmin notificationAdmin; - public ServiceBusTbRuleEngineQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, + public ServiceBusTbRuleEngineQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, TbServiceInfoProvider serviceInfoProvider, TbServiceBusSettings serviceBusSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, TbQueueTransportNotificationSettings transportNotificationSettings, TbServiceBusQueueConfigs serviceBusQueueConfigs) { - this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; @@ -123,7 +123,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact @Override public TbQueueConsumer> createToRuleEngineNotificationsMsgConsumer() { return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, - partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), + notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 1ca7d80394..77738a1e9d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -85,6 +85,7 @@ import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.AsyncCallbackTemplate; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; @@ -157,6 +158,7 @@ public class DefaultTransportService implements TransportService { private final TbTransportQueueFactory queueProvider; private final TbQueueProducerProvider producerProvider; private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final StatsFactory statsFactory; private final TransportDeviceProfileCache deviceProfileCache; @@ -190,6 +192,7 @@ public class DefaultTransportService implements TransportService { TbTransportQueueFactory queueProvider, TbQueueProducerProvider producerProvider, PartitionService partitionService, + NotificationsTopicService notificationsTopicService, StatsFactory statsFactory, TransportDeviceProfileCache deviceProfileCache, TransportTenantProfileCache tenantProfileCache, @@ -200,6 +203,7 @@ public class DefaultTransportService implements TransportService { this.queueProvider = queueProvider; this.producerProvider = producerProvider; this.partitionService = partitionService; + this.notificationsTopicService = notificationsTopicService; this.statsFactory = statsFactory; this.deviceProfileCache = deviceProfileCache; this.tenantProfileCache = tenantProfileCache; @@ -224,7 +228,7 @@ public class DefaultTransportService implements TransportService { ruleEngineMsgProducer = producerProvider.getRuleEngineMsgProducer(); tbCoreMsgProducer = producerProvider.getTbCoreMsgProducer(); transportNotificationsConsumer = queueProvider.createTransportNotificationsConsumer(); - TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceInfoProvider.getServiceId()); + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceInfoProvider.getServiceId()); transportNotificationsConsumer.subscribe(Collections.singleton(tpi)); transportApiRequestTemplate.init(); mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer")); diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index 75978ea371..7049d8ae1c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -39,6 +39,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.TbQueueClusterService; import java.util.List; @@ -56,8 +57,8 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ @Autowired(required = false) private TbQueueAdmin tbQueueAdmin; -// @Autowired(required = false) -// private TbQueueClusterService queueClusterService; + @Autowired(required = false) + private TbQueueClusterService queueClusterService; // @Autowired // private QueueStatsService queueStatsService; @@ -99,7 +100,7 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ //TODO: remove if partitions can't be deleted. if (currentPartitions != oldPartitions && tbQueueAdmin != null) { -// queueClusterService.onQueueDelete(queue, null); + queueClusterService.onQueueDelete(queue, null); if (currentPartitions > oldPartitions) { log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); for (int i = oldPartitions; i < currentPartitions; i++) { @@ -121,9 +122,9 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ public void deleteQueue(TenantId tenantId, QueueId queueId) { log.trace("Executing deleteQueue, queueId: [{}]", queueId); Queue queue = findQueueById(tenantId, queueId); -// if (queueClusterService != null) { -// queueClusterService.onQueueDelete(queue, null); -// } + if (queueClusterService != null) { + queueClusterService.onQueueDelete(queue, null); + } // queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); boolean result = queueDao.removeById(tenantId, queueId.getId()); if (result && tbQueueAdmin != null) { From 061ffcba53ceca03ca27b293cc6290808d04e49a Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 31 Mar 2022 18:24:28 +0200 Subject: [PATCH 05/58] drop queue table in tests --- dao/src/test/resources/sql/hsql/drop-all-tables.sql | 1 + dao/src/test/resources/sql/psql/drop-all-tables.sql | 1 + dao/src/test/resources/sql/timescale/drop-all-tables.sql | 1 + 3 files changed, 3 insertions(+) diff --git a/dao/src/test/resources/sql/hsql/drop-all-tables.sql b/dao/src/test/resources/sql/hsql/drop-all-tables.sql index 095a38533e..3ad3dac3b3 100644 --- a/dao/src/test/resources/sql/hsql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/hsql/drop-all-tables.sql @@ -38,4 +38,5 @@ DROP TABLE IF EXISTS ota_package; DROP TABLE IF EXISTS edge; DROP TABLE IF EXISTS edge_event; DROP TABLE IF EXISTS rpc; +DROP TABLE IF EXISTS queue; DROP FUNCTION IF EXISTS to_uuid; diff --git a/dao/src/test/resources/sql/psql/drop-all-tables.sql b/dao/src/test/resources/sql/psql/drop-all-tables.sql index 3d1d38a0e7..3a6d92a903 100644 --- a/dao/src/test/resources/sql/psql/drop-all-tables.sql +++ b/dao/src/test/resources/sql/psql/drop-all-tables.sql @@ -39,3 +39,4 @@ DROP TABLE IF EXISTS firmware; DROP TABLE IF EXISTS edge; DROP TABLE IF EXISTS edge_event; DROP TABLE IF EXISTS rpc; +DROP TABLE IF EXISTS queue; \ No newline at end of file diff --git a/dao/src/test/resources/sql/timescale/drop-all-tables.sql b/dao/src/test/resources/sql/timescale/drop-all-tables.sql index f113ec5277..735192374d 100644 --- a/dao/src/test/resources/sql/timescale/drop-all-tables.sql +++ b/dao/src/test/resources/sql/timescale/drop-all-tables.sql @@ -34,3 +34,4 @@ DROP TABLE IF EXISTS oauth2_client_registration_template; DROP TABLE IF EXISTS api_usage_state; DROP TABLE IF EXISTS resource; DROP TABLE IF EXISTS firmware; +DROP TABLE IF EXISTS queue; From 4f0f95912ea843319a2b4d9c558db192e4b35add Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 31 Mar 2022 19:42:57 +0200 Subject: [PATCH 06/58] BaseQueueServiceTest is abstract --- .../thingsboard/server/dao/service/BaseQueueServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java index 29490dea04..173f596287 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java @@ -38,7 +38,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class BaseQueueServiceTest extends AbstractServiceTest { +public abstract class BaseQueueServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); From b86a1546e8a9e77e86f41e166324a0f1fd63dbeb Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 1 Apr 2022 13:33:11 +0200 Subject: [PATCH 07/58] created queue routing service --- .../queue/DefaultQueueRoutingInfoService.java | 54 ++++++++++++++++ .../transport/DefaultTransportApiService.java | 36 +++++++++++ common/cluster-api/src/main/proto/queue.proto | 37 +++++++++++ .../queue/discovery/HashPartitionService.java | 2 - .../queue/discovery/QueueRoutingInfo.java | 54 ++++++++++++++++ .../discovery/QueueRoutingInfoService.java | 29 +++++++++ .../common/transport/TransportService.java | 7 ++ .../service/DefaultTransportService.java | 36 +++++++++++ .../TransportQueueRoutingInfoService.java | 64 +++++++++++++++++++ 9 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java new file mode 100644 index 0000000000..df22d42e62 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java @@ -0,0 +1,54 @@ +/** + * 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.queue; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.queue.QueueService; +import org.thingsboard.server.queue.discovery.QueueRoutingInfo; +import org.thingsboard.server.queue.discovery.QueueRoutingInfoService; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core' || '${service.type:null}'=='tb-rule-engine'") +public class DefaultQueueRoutingInfoService implements QueueRoutingInfoService { + + private final QueueService queueService; + + public DefaultQueueRoutingInfoService(QueueService queueService) { + this.queueService = queueService; + } + + @Override + public List getAllQueuesRoutingInfo() { + return queueService.findAllQueues().stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); + } + + @Override + public List getMainQueuesRoutingInfo() { + return queueService.findAllMainQueues().stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); + } + + @Override + public List getQueuesRoutingInfo(TenantId tenantId) { + return queueService.findQueuesByTenantId(tenantId).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 5fda933234..0cba1ec325 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -57,6 +57,7 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageUtil; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; @@ -72,6 +73,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException; import org.thingsboard.server.dao.device.provision.ProvisionRequest; import org.thingsboard.server.dao.device.provision.ProvisionResponse; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.gen.transport.TransportProtos; @@ -99,6 +101,7 @@ import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.resource.TbResourceService; +import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -134,6 +137,7 @@ public class DefaultTransportApiService implements TransportApiService { private final TbResourceService resourceService; private final OtaPackageService otaPackageService; private final OtaPackageDataCache otaPackageDataCache; + private final QueueService queueService; private final ConcurrentMap deviceCreationLocks = new ConcurrentHashMap<>(); @@ -176,6 +180,12 @@ public class DefaultTransportApiService implements TransportApiService { result = handle(transportApiRequestMsg.getDeviceCredentialsRequestMsg()); } else if (transportApiRequestMsg.hasOtaPackageRequestMsg()) { result = handle(transportApiRequestMsg.getOtaPackageRequestMsg()); + } else if (transportApiRequestMsg.hasGetAllMainQueueRoutingInfoRequestMsg()) { + return Futures.transform(handle(transportApiRequestMsg.getGetAllMainQueueRoutingInfoRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); + } else if (transportApiRequestMsg.hasGetTenantQueueRoutingInfoRequestMsg()) { + return Futures.transform(handle(transportApiRequestMsg.getGetTenantQueueRoutingInfoRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); + } else if (transportApiRequestMsg.hasGetAllQueueRoutingInfoRequestMsg()) { + return Futures.transform(handle(transportApiRequestMsg.getGetAllQueueRoutingInfoRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); } return Futures.transform(Optional.ofNullable(result).orElseGet(this::getEmptyTransportApiResponseFuture), @@ -636,6 +646,32 @@ public class DefaultTransportApiService implements TransportApiService { } } + private ListenableFuture handle(TransportProtos.GetAllMainQueueRoutingInfoRequestMsg requestMsg) { + return queuesToTransportApiResponseMsg(queueService.findAllMainQueues()); + } + + private ListenableFuture handle(TransportProtos.GetAllQueueRoutingInfoRequestMsg requestMsg) { + return queuesToTransportApiResponseMsg(queueService.findAllQueues()); + } + + private ListenableFuture handle(TransportProtos.GetTenantQueueRoutingInfoRequestMsg requestMsg) { + TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); + return queuesToTransportApiResponseMsg(queueService.findQueuesByTenantId(tenantId)); + } + + private ListenableFuture queuesToTransportApiResponseMsg(List queues) { + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() + .addAllGetQueueRoutingInfoResponseMsgs(queues.stream() + .map(queue -> TransportProtos.GetQueueRoutingInfoResponseMsg.newBuilder() + .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) + .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) + .setQueueName(queue.getName()) + .setQueueTopic(queue.getTopic()) + .setPartitions(queue.getPartitions()) + .build()).collect(Collectors.toList())).build()); + } + + private Long checkLong(Long l) { return l != null ? l : 0; } diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index a9d517f4dd..1084cb2e44 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -197,6 +197,39 @@ message GetEntityProfileRequestMsg { int64 entityIdLSB = 3; } +message GetAllMainQueueRoutingInfoRequestMsg { +} + +message GetAllQueueRoutingInfoRequestMsg { +} + +message GetTenantQueueRoutingInfoRequestMsg { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; +} + +message GetQueueRoutingInfoResponseMsg { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; + string queueName = 3; + string queueTopic = 4; + int32 partitions = 5; +} + +message QueueUpdateMsg { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; + string queueName = 3; + string queueTopic = 4; + int32 partitions = 5; +} + +message QueueDeleteMsg { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; + string queueName = 3; +} + message LwM2MRegistrationRequestMsg { string tenantId = 1; string endpoint = 2; @@ -673,6 +706,9 @@ message TransportApiRequestMsg { GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11; GetDeviceRequestMsg deviceRequestMsg = 12; GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13; + GetAllMainQueueRoutingInfoRequestMsg GetAllMainQueueRoutingInfoRequestMsg = 14; + GetTenantQueueRoutingInfoRequestMsg getTenantQueueRoutingInfoRequestMsg = 15; + GetAllQueueRoutingInfoRequestMsg getAllQueueRoutingInfoRequestMsg = 16; } /* Response from ThingsBoard Core Service to Transport Service */ @@ -687,6 +723,7 @@ message TransportApiResponseMsg { GetOtaPackageResponseMsg otaPackageResponseMsg = 8; GetDeviceResponseMsg deviceResponseMsg = 9; GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10; + repeated GetQueueRoutingInfoResponseMsg getQueueRoutingInfoResponseMsgs = 11; } /* Messages that are handled by ThingsBoard Core Service */ diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 96df34186c..4e27a01760 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -72,8 +72,6 @@ public class HashPartitionService implements PartitionService { private ConcurrentMap> myPartitions = new ConcurrentHashMap<>(); private ConcurrentMap tpiCache = new ConcurrentHashMap<>(); - private Map tbCoreNotificationTopics = new HashMap<>(); - private Map tbRuleEngineNotificationTopics = new HashMap<>(); private Map> tbTransportServicesByType = new HashMap<>(); private List currentOtherServices; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java new file mode 100644 index 0000000000..8afecc4413 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java @@ -0,0 +1,54 @@ +/** + * 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.queue.discovery; + +import lombok.Data; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.gen.transport.TransportProtos.GetQueueRoutingInfoResponseMsg; + +import java.util.UUID; + + +@Data +public class QueueRoutingInfo { + + private final TenantId tenantId; + private final String queueName; + private final String queueTopic; + private final int partitions; + + public QueueRoutingInfo(TenantId tenantId, String queueName, String queueTopic, int partitions) { + this.tenantId = tenantId; + this.queueName = queueName; + this.queueTopic = queueTopic; + this.partitions = partitions; + } + + public QueueRoutingInfo(Queue queue) { + this.tenantId = queue.getTenantId(); + this.queueName = queue.getName(); + this.queueTopic = queue.getTopic(); + this.partitions = queue.getPartitions(); + } + + public QueueRoutingInfo(GetQueueRoutingInfoResponseMsg routingInfo) { + this.tenantId = new TenantId(new UUID(routingInfo.getTenantIdMSB(), routingInfo.getTenantIdLSB())); + this.queueName = routingInfo.getQueueName(); + this.queueTopic = routingInfo.getQueueTopic(); + this.partitions = routingInfo.getPartitions(); + } +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java new file mode 100644 index 0000000000..366452d9e8 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java @@ -0,0 +1,29 @@ +/** + * 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.queue.discovery; + +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.List; + +public interface QueueRoutingInfoService { + + List getAllQueuesRoutingInfo(); + + List getMainQueuesRoutingInfo(); + + List getQueuesRoutingInfo(TenantId tenantId); +} diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java index 6c788d93f3..53c1997f5c 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java @@ -57,6 +57,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MC import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; @@ -67,6 +68,12 @@ public interface TransportService { GetEntityProfileResponseMsg getEntityProfile(GetEntityProfileRequestMsg msg); + List getQueueRoutingInfo(TransportProtos.GetAllMainQueueRoutingInfoRequestMsg msg); + + List getQueueRoutingInfo(TransportProtos.GetTenantQueueRoutingInfoRequestMsg msg); + + List getQueueRoutingInfo(TransportProtos.GetAllQueueRoutingInfoRequestMsg msg); + GetResourceResponseMsg getResource(GetResourceRequestMsg msg); GetSnmpDevicesResponseMsg getSnmpDevicesIds(GetSnmpDevicesRequestMsg requestMsg); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 77738a1e9d..3de2a6a7d5 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -304,6 +304,42 @@ public class DefaultTransportService implements TransportService { } } + @Override + public List getQueueRoutingInfo(TransportProtos.GetAllQueueRoutingInfoRequestMsg msg) { + TbProtoQueueMsg protoMsg = + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetAllQueueRoutingInfoRequestMsg(msg).build()); + try { + TbProtoQueueMsg response = transportApiRequestTemplate.send(protoMsg).get(); + return response.getValue().getGetQueueRoutingInfoResponseMsgsList(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + @Override + public List getQueueRoutingInfo(TransportProtos.GetAllMainQueueRoutingInfoRequestMsg msg) { + TbProtoQueueMsg protoMsg = + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetAllMainQueueRoutingInfoRequestMsg(msg).build()); + try { + TbProtoQueueMsg response = transportApiRequestTemplate.send(protoMsg).get(); + return response.getValue().getGetQueueRoutingInfoResponseMsgsList(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + @Override + public List getQueueRoutingInfo(TransportProtos.GetTenantQueueRoutingInfoRequestMsg msg) { + TbProtoQueueMsg protoMsg = + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetTenantQueueRoutingInfoRequestMsg(msg).build()); + try { + TbProtoQueueMsg response = transportApiRequestTemplate.send(protoMsg).get(); + return response.getValue().getGetQueueRoutingInfoResponseMsgsList(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + @Override public TransportProtos.GetResourceResponseMsg getResource(TransportProtos.GetResourceRequestMsg msg) { TbProtoQueueMsg protoMsg = diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java new file mode 100644 index 0000000000..bcdc07b5b0 --- /dev/null +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java @@ -0,0 +1,64 @@ +/** + * 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.common.transport.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.gen.transport.TransportProtos.GetAllQueueRoutingInfoRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.GetAllMainQueueRoutingInfoRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.GetTenantQueueRoutingInfoRequestMsg; +import org.thingsboard.server.queue.discovery.QueueRoutingInfo; +import org.thingsboard.server.queue.discovery.QueueRoutingInfoService; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@ConditionalOnExpression("'${service.type:null}'=='tb-transport'") +public class TransportQueueRoutingInfoService implements QueueRoutingInfoService { + + private TransportService transportService; + + @Lazy + @Autowired + public void setTransportService(TransportService transportService) { + this.transportService = transportService; + } + + @Override + public List getAllQueuesRoutingInfo() { + GetAllQueueRoutingInfoRequestMsg msg = GetAllQueueRoutingInfoRequestMsg.newBuilder().build(); + return transportService.getQueueRoutingInfo(msg).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); + } + + @Override + public List getMainQueuesRoutingInfo() { + GetAllMainQueueRoutingInfoRequestMsg msg = GetAllMainQueueRoutingInfoRequestMsg.newBuilder().build(); + return transportService.getQueueRoutingInfo(msg).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); + } + + @Override + public List getQueuesRoutingInfo(TenantId tenantId) { + GetTenantQueueRoutingInfoRequestMsg msg = GetTenantQueueRoutingInfoRequestMsg.newBuilder().build(); + return transportService.getQueueRoutingInfo(msg).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); + } +} From 5c2ee4434c95d487411f60f09f1db14df7be6ade Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 4 Apr 2022 17:06:40 +0200 Subject: [PATCH 08/58] added consumerPerPartition to Queue entity --- .../thingsboard/server/common/data/queue/Queue.java | 1 + .../thingsboard/server/dao/model/ModelConstants.java | 1 + .../thingsboard/server/dao/model/sql/QueueEntity.java | 5 +++++ dao/src/main/resources/sql/schema-entities.sql | 1 + .../server/dao/service/BaseQueueServiceTest.java | 2 +- .../home/pages/admin/queue/queue.component.html | 11 ++++++++++- .../modules/home/pages/admin/queue/queue.component.ts | 2 ++ ui-ngx/src/app/shared/models/queue.models.ts | 1 + ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 ++ 9 files changed, 24 insertions(+), 2 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java index 84776c88f4..004bd0057d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java @@ -29,6 +29,7 @@ public class Queue extends BaseData implements HasName, HasTenantId { private String topic; private int pollInterval; private int partitions; + private boolean consumerPerPartition; private long packProcessingTimeout; private SubmitStrategy submitStrategy; private ProcessingStrategy processingStrategy; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index cb209c2ee7..73c19cab3c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -592,6 +592,7 @@ public class ModelConstants { public static final String QUEUE_TOPIC_PROPERTY = "topic"; public static final String QUEUE_POLL_INTERVAL_PROPERTY = "poll_interval"; public static final String QUEUE_PARTITIONS_PROPERTY = "partitions"; + public static final String QUEUE_CONSUMER_PER_PARTITION = "consumer_per_partition"; public static final String QUEUE_PACK_PROCESSING_TIMEOUT_PROPERTY = "pack_processing_timeout"; public static final String QUEUE_SUBMIT_STRATEGY_PROPERTY = "submit_strategy"; public static final String QUEUE_PROCESSING_STRATEGY_PROPERTY = "processing_strategy"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java index 3791ab4ac3..fefe686c9e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java @@ -59,6 +59,9 @@ public class QueueEntity extends BaseSqlEntity { @Column(name = ModelConstants.QUEUE_PARTITIONS_PROPERTY) private int partitions; + @Column(name = ModelConstants.QUEUE_CONSUMER_PER_PARTITION) + private boolean consumerPerPartition; + @Column(name = ModelConstants.QUEUE_PACK_PROCESSING_TIMEOUT_PROPERTY) private long packProcessingTimeout; @@ -83,6 +86,7 @@ public class QueueEntity extends BaseSqlEntity { this.topic = queue.getTopic(); this.pollInterval = queue.getPollInterval(); this.partitions = queue.getPartitions(); + this.consumerPerPartition = queue.isConsumerPerPartition(); this.packProcessingTimeout = queue.getPackProcessingTimeout(); this.submitStrategy = mapper.valueToTree(queue.getSubmitStrategy()); this.processingStrategy = mapper.valueToTree(queue.getProcessingStrategy()); @@ -97,6 +101,7 @@ public class QueueEntity extends BaseSqlEntity { queue.setTopic(topic); queue.setPollInterval(pollInterval); queue.setPartitions(partitions); + queue.setConsumerPerPartition(consumerPerPartition); queue.setPackProcessingTimeout(packProcessingTimeout); queue.setSubmitStrategy(mapper.convertValue(this.submitStrategy, SubmitStrategy.class)); queue.setProcessingStrategy(mapper.convertValue(this.processingStrategy, ProcessingStrategy.class)); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 5335ce6f5f..54c3cbfa93 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -642,6 +642,7 @@ CREATE TABLE IF NOT EXISTS queue( topic varchar(255), poll_interval int, partitions int, + consumer_per_partition boolean, pack_processing_timeout bigint, submit_strategy varchar(255), processing_strategy varchar(255) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java index 173f596287..8899224bd5 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java @@ -150,7 +150,7 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest { } @Test(expected = DataValidationException.class) - public void testSaveQueueWithEmptyPoolInterval() { + public void testSaveQueueWithEmptyPollInterval() { Queue queue = new Queue(); queue.setTenantId(tenantId); queue.setName("Test"); diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html index ae163d9ba7..ae8f08e348 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html @@ -56,6 +56,16 @@ {{ 'queue.partitions-min-value' | translate }} + + + + + + +
{{ 'queue.consumer-per-partition' | translate }}
+
{{'queue.consumer-per-partition-hint' | translate}}
+
+ queue.processing-timeout @@ -69,7 +79,6 @@
- diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts index b694e21ddf..f9a60773df 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts @@ -71,6 +71,7 @@ export class QueueComponent extends EntityComponent { entity && entity.partitions ? entity.partitions : 10, [Validators.min(1), Validators.required] ], + consumerPerPartition: [entity ? entity.consumerPerPartition : false, []], packProcessingTimeout: [ entity && entity.packProcessingTimeout ? entity.packProcessingTimeout : 2000, [Validators.min(1), Validators.required] @@ -118,6 +119,7 @@ export class QueueComponent extends EntityComponent { name: entity.name, pollInterval: entity.pollInterval, partitions: entity.partitions, + consumerPerPartition: entity.consumerPerPartition, packProcessingTimeout: entity.packProcessingTimeout, submitStrategy: { type: entity.submitStrategy?.type, diff --git a/ui-ngx/src/app/shared/models/queue.models.ts b/ui-ngx/src/app/shared/models/queue.models.ts index 2fe2f511f4..508cf2aee1 100644 --- a/ui-ngx/src/app/shared/models/queue.models.ts +++ b/ui-ngx/src/app/shared/models/queue.models.ts @@ -45,6 +45,7 @@ export enum QueueProcessingStrategyTypes { export interface QueueInfo extends BaseData { packProcessingTimeout: number; partitions: number; + consumerPerPartition: boolean, pollInterval: number; processingStrategy: { type: QueueProcessingStrategyTypes, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 75dbdf4f5f..4e30b773b1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2714,6 +2714,8 @@ "processing-strategy": "Processing Strategy", "poll-interval": "Poll interval", "partitions": "Partitions", + "consumer-per-partition": "Consumer per partition", + "consumer-per-partition-hint": "Enable separate consumer(s) per each partition", "processing-timeout": "Processing timeout", "batch-size": "Batch size", "retries": "Retries (0 - unlimited)", From 3592351a63f2ff3ff99d905735ba7aad5e8b1daf Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 11 Apr 2022 11:03:14 +0200 Subject: [PATCH 09/58] Used Queue entity --- .../server/controller/QueueController.java | 14 +- .../install/ThingsboardInstallService.java | 1 + .../DefaultSystemDataLoaderService.java | 74 ++++++++ .../install/SystemDataLoaderService.java | 1 + .../queue/DefaultTbClusterService.java | 157 ++++++++-------- .../queue/DefaultTbCoreConsumerService.java | 14 +- .../DefaultTbRuleEngineConsumerService.java | 124 ++++++++++--- .../TbTopicWithConsumerPerPartition.java | 2 - ...TbRuleEngineProcessingStrategyFactory.java | 37 ++-- .../TbRuleEngineSubmitStrategyFactory.java | 19 +- .../server/controller/AbstractWebTest.java | 5 + .../routing/HashPartitionServiceTest.java | 20 +- common/cluster-api/src/main/proto/queue.proto | 18 +- .../server/queue/DefaultTbQueueService.java | 2 +- .../DefaultTbServiceInfoProvider.java | 12 -- .../queue/discovery/HashPartitionService.java | 173 +++++++++++++----- .../queue/discovery/PartitionService.java | 8 + .../discovery/TbServiceInfoProvider.java | 2 + .../kafka/TbKafkaConsumerStatsService.java | 7 +- .../provider/AwsSqsMonolithQueueFactory.java | 4 +- .../AwsSqsTbRuleEngineQueueFactory.java | 4 +- .../InMemoryMonolithQueueFactory.java | 4 +- .../provider/KafkaMonolithQueueFactory.java | 4 +- .../KafkaTbRuleEngineQueueFactory.java | 4 +- .../provider/PubSubMonolithQueueFactory.java | 4 +- .../PubSubTbRuleEngineQueueFactory.java | 4 +- .../RabbitMqMonolithQueueFactory.java | 4 +- .../RabbitMqTbRuleEngineQueueFactory.java | 4 +- .../ServiceBusMonolithQueueFactory.java | 4 +- .../ServiceBusTbRuleEngineQueueFactory.java | 4 +- .../provider/TbRuleEngineQueueFactory.java | 4 +- .../usagestats/DefaultTbApiUsageClient.java | 6 +- .../service/DefaultTransportService.java | 22 ++- .../TransportQueueRoutingInfoService.java | 6 +- .../dao/device/DeviceProfileServiceImpl.java | 23 ++- .../server/dao/queue/BaseQueueService.java | 28 ++- docker/docker-compose.yml | 14 ++ .../queue/queue-type-list.component.html | 2 +- .../assets/locale/locale.constant-en_US.json | 2 + 39 files changed, 563 insertions(+), 278 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index fef6fb9027..c48fc8036f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -33,13 +33,14 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; -import org.thingsboard.server.queue.TbQueueService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import java.util.Collections; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_DESCRIPTION; @@ -51,8 +52,6 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHO @RequiredArgsConstructor public class QueueController extends BaseController { - private final TbQueueService tbQueueService; - @ApiOperation(value = "Get queue names (getTenantQueuesByServiceType)", notes = "Returns a set of unique queue names based on service type. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -62,8 +61,13 @@ public class QueueController extends BaseController { @RequestParam String serviceType) throws ThingsboardException { checkParameter("serviceType", serviceType); try { - //TODO: replace for using new QueueService - return tbQueueService.getQueuesByServiceType(ServiceType.valueOf(serviceType)); + ServiceType type = ServiceType.valueOf(serviceType); + switch (type) { + case TB_RULE_ENGINE: + return queueService.findQueuesByTenantId(getTenantId()).stream().map(Queue::getName).collect(Collectors.toSet()); + default: + return Collections.emptySet(); + } } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 597b70275b..49d320e3e9 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -255,6 +255,7 @@ public class ThingsboardInstallService { systemDataLoaderService.createAdminSettings(); systemDataLoaderService.loadSystemWidgets(); systemDataLoaderService.createOAuth2Templates(); + systemDataLoaderService.createQueues(); // systemDataLoaderService.loadSystemPlugins(); // systemDataLoaderService.loadSystemRules(); diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index c5bdf722af..37982f4a6d 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -68,6 +68,11 @@ import org.thingsboard.server.common.data.query.DynamicValueSourceType; import org.thingsboard.server.common.data.query.EntityKeyValueType; import org.thingsboard.server.common.data.query.FilterPredicateValue; import org.thingsboard.server.common.data.query.NumericFilterPredicate; +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.RuleChainType; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.DeviceCredentials; @@ -81,6 +86,7 @@ import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.tenant.TenantProfileService; @@ -155,6 +161,9 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @Getter private boolean persistActivityToTelemetry; + @Autowired + private QueueService queueService; + @Bean protected BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); @@ -575,4 +584,69 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { }, tsCallBackExecutor); } + @Override + public void createQueues() { + Queue mainQueue = new Queue(); + mainQueue.setTenantId(TenantId.SYS_TENANT_ID); + mainQueue.setName("Main"); + mainQueue.setTopic("tb_rule_engine.main"); + mainQueue.setPollInterval(25); + mainQueue.setPartitions(10); + mainQueue.setConsumerPerPartition(true); + mainQueue.setPackProcessingTimeout(2000); + SubmitStrategy mainQueueSubmitStrategy = new SubmitStrategy(); + mainQueueSubmitStrategy.setType(SubmitStrategyType.BURST); + mainQueueSubmitStrategy.setBatchSize(1000); + mainQueue.setSubmitStrategy(mainQueueSubmitStrategy); + ProcessingStrategy mainQueueProcessingStrategy = new ProcessingStrategy(); + mainQueueProcessingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES); + mainQueueProcessingStrategy.setRetries(3); + mainQueueProcessingStrategy.setFailurePercentage(0); + mainQueueProcessingStrategy.setPauseBetweenRetries(3); + mainQueueProcessingStrategy.setMaxPauseBetweenRetries(3); + mainQueue.setProcessingStrategy(mainQueueProcessingStrategy); + queueService.saveQueue(mainQueue); + + Queue highPriorityQueue = new Queue(); + highPriorityQueue.setTenantId(TenantId.SYS_TENANT_ID); + highPriorityQueue.setName("HighPriority"); + highPriorityQueue.setTopic("tb_rule_engine.hp"); + highPriorityQueue.setPollInterval(25); + highPriorityQueue.setPartitions(10); + highPriorityQueue.setConsumerPerPartition(true); + highPriorityQueue.setPackProcessingTimeout(2000); + SubmitStrategy highPriorityQueueSubmitStrategy = new SubmitStrategy(); + highPriorityQueueSubmitStrategy.setType(SubmitStrategyType.BURST); + highPriorityQueueSubmitStrategy.setBatchSize(100); + highPriorityQueue.setSubmitStrategy(highPriorityQueueSubmitStrategy); + ProcessingStrategy highPriorityQueueProcessingStrategy = new ProcessingStrategy(); + highPriorityQueueProcessingStrategy.setType(ProcessingStrategyType.RETRY_FAILED_AND_TIMED_OUT); + highPriorityQueueProcessingStrategy.setRetries(0); + highPriorityQueueProcessingStrategy.setFailurePercentage(0); + highPriorityQueueProcessingStrategy.setPauseBetweenRetries(5); + highPriorityQueueProcessingStrategy.setMaxPauseBetweenRetries(5); + highPriorityQueue.setProcessingStrategy(highPriorityQueueProcessingStrategy); + queueService.saveQueue(highPriorityQueue); + + Queue sequentialByOriginatorQueue = new Queue(); + sequentialByOriginatorQueue.setTenantId(TenantId.SYS_TENANT_ID); + sequentialByOriginatorQueue.setName("SequentialByOriginator"); + sequentialByOriginatorQueue.setTopic("tb_rule_engine.sq"); + sequentialByOriginatorQueue.setPollInterval(25); + sequentialByOriginatorQueue.setPartitions(10); + sequentialByOriginatorQueue.setPackProcessingTimeout(2000); + sequentialByOriginatorQueue.setConsumerPerPartition(true); + SubmitStrategy sequentialByOriginatorQueueSubmitStrategy = new SubmitStrategy(); + sequentialByOriginatorQueueSubmitStrategy.setType(SubmitStrategyType.SEQUENTIAL_BY_ORIGINATOR); + sequentialByOriginatorQueueSubmitStrategy.setBatchSize(100); + sequentialByOriginatorQueue.setSubmitStrategy(sequentialByOriginatorQueueSubmitStrategy); + ProcessingStrategy sequentialByOriginatorQueueProcessingStrategy = new ProcessingStrategy(); + sequentialByOriginatorQueueProcessingStrategy.setType(ProcessingStrategyType.RETRY_FAILED_AND_TIMED_OUT); + sequentialByOriginatorQueueProcessingStrategy.setRetries(3); + sequentialByOriginatorQueueProcessingStrategy.setFailurePercentage(0); + sequentialByOriginatorQueueProcessingStrategy.setPauseBetweenRetries(5); + sequentialByOriginatorQueueProcessingStrategy.setMaxPauseBetweenRetries(5); + sequentialByOriginatorQueue.setProcessingStrategy(sequentialByOriginatorQueueProcessingStrategy); + queueService.saveQueue(sequentialByOriginatorQueue); + } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java index aca458bd15..1ceb1be289 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java @@ -33,4 +33,5 @@ public interface SystemDataLoaderService { void deleteSystemWidgetBundle(String bundleAlias) throws Exception; + void createQueues(); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index ebe99d99e0..8f1db53764 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -96,11 +96,17 @@ public class DefaultTbClusterService implements TbClusterService { @Lazy private PartitionService partitionService; - private final TbQueueProducerProvider producerProvider; + @Autowired + @Lazy + private TbQueueProducerProvider producerProvider; + + @Autowired + @Lazy + private OtaPackageStateService otaPackageStateService; + private final NotificationsTopicService notificationsTopicService; private final DataDecodingEncodingService encodingService; private final TbDeviceProfileCache deviceProfileCache; - private final OtaPackageStateService otaPackageStateService; private final GatewayNotificationsService gatewayNotificationsService; @Override @@ -486,88 +492,81 @@ public class DefaultTbClusterService implements TbClusterService { public void onQueueChange(Queue queue, TbQueueCallback callback) { log.trace("[{}][{}] Processing queue change [{}] event", queue.getTenantId(), queue.getId(), queue.getName()); -// TransportProtos.QueueUpdateMsg queueUpdateMsg = TransportProtos.QueueUpdateMsg.newBuilder() -// .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) -// .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) -// .setQueueName(queue.getName()) -// .setQueueTopic(queue.getTopic()) -// .setPartitions(queue.getPartitions()) -// .build(); -// -// if ("Main".equals(queue.getName())) { -// Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); -// ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); -// for (TransportProtos.ServiceInfo transportService : tbTransportServices) { -// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); -// producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); -// toTransportNfs.incrementAndGet(); -// } -// -// Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); -// ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); -// for (TransportProtos.ServiceInfo coreService : tbCoreServices) { -// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); -// producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); -// toCoreNfs.incrementAndGet(); -// } -// } else { -// Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); -// ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); -// for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { -// TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); -// if (tenantId.equals(queue.getTenantId())) { -// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); -// producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); -// toRuleEngineNfs.incrementAndGet(); -// } -// } -// } + TransportProtos.QueueUpdateMsg queueUpdateMsg = TransportProtos.QueueUpdateMsg.newBuilder() + .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) + .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) + .setQueueName(queue.getName()) + .setQueueTopic(queue.getTopic()) + .setPartitions(queue.getPartitions()) + .build(); + + if ("Main".equals(queue.getName())) { + Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + for (TransportProtos.ServiceInfo transportService : tbTransportServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); + producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); + toTransportNfs.incrementAndGet(); + } + + Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); + ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + for (TransportProtos.ServiceInfo coreService : tbCoreServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); + producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); + toCoreNfs.incrementAndGet(); + } + } else { + Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); + ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { + TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); + if (tenantId.equals(queue.getTenantId())) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); + producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); + toRuleEngineNfs.incrementAndGet(); + } + } + } } @Override public void onQueueDelete(Queue queue, TbQueueCallback callback) { log.trace("[{}][{}] Processing queue delete [{}] event", queue.getTenantId(), queue.getId(), queue.getName()); -// TransportProtos.QueueDeleteMsg queueDeleteMsg = TransportProtos.QueueDeleteMsg.newBuilder() -// .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) -// .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) -// .setQueueName(queue.getName()) -// .build(); -// -// if ("Main".equals(queue.getName())) { -// Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); -// ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); -// for (TransportProtos.ServiceInfo transportService : tbTransportServices) { -// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); -// producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); -// toTransportNfs.incrementAndGet(); -// } -// -// Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); -// ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); -// for (TransportProtos.ServiceInfo coreService : tbCoreServices) { -// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); -// producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); -// toCoreNfs.incrementAndGet(); -// } -// } else { -// //TODO: 3.2 should be changed with smth like TransportApiRequestTemplate and get responses from all RE's -// Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); -// ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); -// for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { -// TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); -// if (tenantId.equals(queue.getTenantId())) { -// TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); -// log.info("Send notification about deleting queue [{}] to Rule Engine [{}]", queue.getName(), tpi.getFullTopicName()); -// producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); -// toRuleEngineNfs.incrementAndGet(); -// } -// } -// try { -// Thread.sleep(3000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// } + TransportProtos.QueueDeleteMsg queueDeleteMsg = TransportProtos.QueueDeleteMsg.newBuilder() + .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) + .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) + .setQueueName(queue.getName()) + .build(); + + if ("Main".equals(queue.getName())) { + Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + for (TransportProtos.ServiceInfo transportService : tbTransportServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); + producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); + toTransportNfs.incrementAndGet(); + } + + Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); + ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + for (TransportProtos.ServiceInfo coreService : tbCoreServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); + producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); + toCoreNfs.incrementAndGet(); + } + } else { + Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); + ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { + TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); + if (tenantId.equals(queue.getTenantId())) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); + producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); + toRuleEngineNfs.incrementAndGet(); + } + } + } } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index f1bd296e5f..7113272187 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.EdgeNotificationMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto; @@ -57,6 +58,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceM import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -115,6 +117,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> usageStatsConsumer; private final TbQueueConsumer> firmwareStatesConsumer; @@ -135,7 +138,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService>> consumers = new ConcurrentHashMap<>(); - private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>(); + private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>(); private final ConcurrentMap consumerStats = new ConcurrentHashMap<>(); private final ConcurrentMap topicsConsumerPerPartition = new ConcurrentHashMap<>(); final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); @@ -108,7 +114,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< public DefaultTbRuleEngineConsumerService(TbRuleEngineProcessingStrategyFactory processingStrategyFactory, TbRuleEngineSubmitStrategyFactory submitStrategyFactory, - TbQueueRuleEngineSettings ruleEngineSettings, TbRuleEngineQueueFactory tbRuleEngineQueueFactory, RuleEngineStatisticsService statisticsService, ActorSystemContext actorContext, @@ -117,28 +122,37 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< StatsFactory statsFactory, TbDeviceProfileCache deviceProfileCache, TbTenantProfileCache tenantProfileCache, - TbApiUsageStateService apiUsageStateService) { + TbApiUsageStateService apiUsageStateService, + PartitionService partitionService, TbServiceInfoProvider serviceInfoProvider, QueueService queueService) { super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, apiUsageStateService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer()); this.statisticsService = statisticsService; - this.ruleEngineSettings = ruleEngineSettings; this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory; this.submitStrategyFactory = submitStrategyFactory; this.processingStrategyFactory = processingStrategyFactory; this.tbDeviceRpcService = tbDeviceRpcService; this.statsFactory = statsFactory; + this.partitionService = partitionService; + this.serviceInfoProvider = serviceInfoProvider; + this.queueService = queueService; + this.tenantId = actorContext.getServiceInfoProvider().getIsolatedTenant().orElse(TenantId.SYS_TENANT_ID); } @PostConstruct public void init() { super.init("tb-rule-engine-consumer", "tb-rule-engine-notifications-consumer"); - for (TbRuleEngineQueueConfiguration configuration : ruleEngineSettings.getQueues()) { - consumerConfigurations.putIfAbsent(configuration.getName(), configuration); - consumerStats.put(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName(), statsFactory)); - if (!configuration.isConsumerPerPartition()) { - consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); - } else { - topicsConsumerPerPartition.computeIfAbsent(configuration.getName(), TbTopicWithConsumerPerPartition::new); - } + List queues = queueService.findQueuesByTenantId(tenantId); + for (Queue configuration : queues) { + initConsumer(configuration); + } + } + + private void initConsumer(Queue configuration) { + consumerConfigurations.putIfAbsent(configuration.getName(), configuration); + consumerStats.putIfAbsent(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName(), statsFactory)); + if (!configuration.isConsumerPerPartition()) { + consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); + } else { + topicsConsumerPerPartition.computeIfAbsent(configuration.getName(), TbTopicWithConsumerPerPartition::new); } } @@ -147,7 +161,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< super.destroy(); submitExecutor.shutdownNow(); repartitionExecutor.shutdownNow(); - ruleEngineSettings.getQueues().forEach(config -> consumerConfigurations.put(config.getName(), config)); } @Override @@ -178,7 +191,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< return; } TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueName); - Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); + java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); if (subscribeQueue.isEmpty()) { return; } @@ -207,7 +220,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< addedPartitions.forEach((tpi) -> { log.info("[{}] Adding consumer for topic: {}", queueName, tpi); - TbRuleEngineQueueConfiguration configuration = consumerConfigurations.get(queueName); + Queue configuration = consumerConfigurations.get(queueName); TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); consumers.put(tpi, consumer); launchConsumer(consumer, consumerConfigurations.get(queueName), consumerStats.get(queueName), "" + queueName + "-" + tpi.getPartition().orElse(-999999)); @@ -241,11 +254,11 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< .forEach((tpi) -> removeConsumerForTopicByTpi(tbTopicWithConsumerPerPartition.getTopic(), tbTopicWithConsumerPerPartition.getConsumers(), tpi))); } - void launchConsumer(TbQueueConsumer> consumer, TbRuleEngineQueueConfiguration configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { + void launchConsumer(TbQueueConsumer> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix)); } - void consumerLoop(TbQueueConsumer> consumer, TbRuleEngineQueueConfiguration configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { + void consumerLoop(TbQueueConsumer> consumer, org.thingsboard.server.common.data.queue.Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { updateCurrentThreadName(threadSuffix); while (!stopped && !consumer.isStopped()) { try { @@ -310,15 +323,15 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< Thread.currentThread().setName(name); } - TbRuleEngineProcessingStrategy getAckStrategy(TbRuleEngineQueueConfiguration configuration) { + TbRuleEngineProcessingStrategy getAckStrategy(Queue configuration) { return processingStrategyFactory.newInstance(configuration.getName(), configuration.getProcessingStrategy()); } - TbRuleEngineSubmitStrategy getSubmitStrategy(TbRuleEngineQueueConfiguration configuration) { + TbRuleEngineSubmitStrategy getSubmitStrategy(Queue configuration) { return submitStrategyFactory.newInstance(configuration.getName(), configuration.getSubmitStrategy()); } - void submitMessage(TbRuleEngineQueueConfiguration configuration, TbRuleEngineConsumerStats stats, TbMsgPackProcessingContext ctx, UUID id, TbProtoQueueMsg msg) { + void submitMessage(Queue configuration, TbRuleEngineConsumerStats stats, TbMsgPackProcessingContext ctx, UUID id, TbProtoQueueMsg msg) { log.trace("[{}] Creating callback for topic {} message: {}", id, configuration.getName(), msg.getValue()); ToRuleEngineMsg toRuleEngineMsg = msg.getValue(); TenantId tenantId = TenantId.fromUUID(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB())); @@ -336,7 +349,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } - private void printFirstOrAll(TbRuleEngineQueueConfiguration configuration, TbMsgPackProcessingContext ctx, Map> map, String prefix) { + private void printFirstOrAll(Queue configuration, TbMsgPackProcessingContext ctx, Map> map, String prefix) { boolean printAll = log.isTraceEnabled(); log.info("{} to process [{}] messages", prefix, map.size()); for (Map.Entry> pending : map.entrySet()) { @@ -380,12 +393,67 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< , proto.getResponse(), error); tbDeviceRpcService.processRpcResponseFromDevice(response); callback.onSuccess(); + } else if (nfMsg.hasQueueUpdateMsg()) { + updateQueue(nfMsg.getQueueUpdateMsg()); + callback.onSuccess(); + } else if (nfMsg.hasQueueDeleteMsg()) { + deleteQueue(nfMsg.getQueueDeleteMsg()); + callback.onSuccess(); } else { log.trace("Received notification with missing handler"); callback.onSuccess(); } } + private void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { + String queueName = queueUpdateMsg.getQueueName(); + Queue queue = queueService.findQueueByTenantIdAndName(tenantId, queueName); + Queue oldQueue = consumerConfigurations.remove(queueName); + if (oldQueue != null) { + if (oldQueue.isConsumerPerPartition()) { + TbTopicWithConsumerPerPartition consumerPerPartition = topicsConsumerPerPartition.remove(queueName); + ReentrantLock lock = consumerPerPartition.getLock(); + try { + lock.lock(); + consumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe); + } finally { + lock.unlock(); + } + } else { + TbQueueConsumer> consumer = consumers.remove(queueName); + consumer.unsubscribe(); + } + } + + initConsumer(queue); + + if (!queue.isConsumerPerPartition()) { + launchConsumer(consumers.get(queueName), consumerConfigurations.get(queueName), consumerStats.get(queueName), queueName); + } + + partitionService.updateQueue(queueUpdateMsg); + partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); + } + + private void deleteQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { + Queue queue = consumerConfigurations.remove(queueDeleteMsg.getQueueName()); + if (queue != null) { + if (queue.isConsumerPerPartition()) { + TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.remove(queueDeleteMsg.getQueueName()); + if (tbTopicWithConsumerPerPartition != null) { + tbTopicWithConsumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe); + tbTopicWithConsumerPerPartition.getConsumers().clear(); + } + } else { + TbQueueConsumer> consumer = consumers.remove(queueDeleteMsg.getQueueName()); + if (consumer != null) { + consumer.unsubscribe(); + } + } + } + partitionService.removeQueue(queueDeleteMsg); + } + private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback); QueueToRuleEngineMsg msg; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbTopicWithConsumerPerPartition.java b/application/src/main/java/org/thingsboard/server/service/queue/TbTopicWithConsumerPerPartition.java index b1696dcc1e..e51b345f98 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbTopicWithConsumerPerPartition.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbTopicWithConsumerPerPartition.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.queue; -import lombok.Builder; import lombok.Data; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -25,7 +24,6 @@ import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import java.util.Collections; -import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java index 02774207b0..3056e65c78 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.queue.processing; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import org.thingsboard.server.gen.transport.TransportProtos; @@ -33,22 +34,22 @@ import java.util.concurrent.TimeUnit; @Slf4j public class TbRuleEngineProcessingStrategyFactory { - public TbRuleEngineProcessingStrategy newInstance(String name, TbRuleEngineQueueAckStrategyConfiguration configuration) { - switch (configuration.getType()) { - case "SKIP_ALL_FAILURES": + public TbRuleEngineProcessingStrategy newInstance(String name, ProcessingStrategy processingStrategy) { + switch (processingStrategy.getType()) { + case SKIP_ALL_FAILURES: return new SkipStrategy(name, false); - case "SKIP_ALL_FAILURES_AND_TIMED_OUT": + case SKIP_ALL_FAILURES_AND_TIMED_OUT: return new SkipStrategy(name, true); - case "RETRY_ALL": - return new RetryStrategy(name, true, true, true, configuration); - case "RETRY_FAILED": - return new RetryStrategy(name, false, true, false, configuration); - case "RETRY_TIMED_OUT": - return new RetryStrategy(name, false, false, true, configuration); - case "RETRY_FAILED_AND_TIMED_OUT": - return new RetryStrategy(name, false, true, true, configuration); + case RETRY_ALL: + return new RetryStrategy(name, true, true, true, processingStrategy); + case RETRY_FAILED: + return new RetryStrategy(name, false, true, false, processingStrategy); + case RETRY_TIMED_OUT: + return new RetryStrategy(name, false, false, true, processingStrategy); + case RETRY_FAILED_AND_TIMED_OUT: + return new RetryStrategy(name, false, true, true, processingStrategy); default: - throw new RuntimeException("TbRuleEngineProcessingStrategy with type " + configuration.getType() + " is not supported!"); + throw new RuntimeException("TbRuleEngineProcessingStrategy with type " + processingStrategy.getType() + " is not supported!"); } } @@ -66,15 +67,15 @@ public class TbRuleEngineProcessingStrategyFactory { private int initialTotalCount; private int retryCount; - public RetryStrategy(String queueName, boolean retrySuccessful, boolean retryFailed, boolean retryTimeout, TbRuleEngineQueueAckStrategyConfiguration configuration) { + public RetryStrategy(String queueName, boolean retrySuccessful, boolean retryFailed, boolean retryTimeout, ProcessingStrategy processingStrategy) { this.queueName = queueName; this.retrySuccessful = retrySuccessful; this.retryFailed = retryFailed; this.retryTimeout = retryTimeout; - this.maxRetries = configuration.getRetries(); - this.maxAllowedFailurePercentage = configuration.getFailurePercentage(); - this.pauseBetweenRetries = configuration.getPauseBetweenRetries(); - this.maxPauseBetweenRetries = configuration.getMaxPauseBetweenRetries(); + this.maxRetries = processingStrategy.getRetries(); + this.maxAllowedFailurePercentage = processingStrategy.getFailurePercentage(); + this.pauseBetweenRetries = processingStrategy.getPauseBetweenRetries(); + this.maxPauseBetweenRetries = processingStrategy.getMaxPauseBetweenRetries(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineSubmitStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineSubmitStrategyFactory.java index 3c4d538394..5c4d3b14ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineSubmitStrategyFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineSubmitStrategyFactory.java @@ -17,26 +17,27 @@ package org.thingsboard.server.service.queue.processing; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.SubmitStrategy; import org.thingsboard.server.queue.settings.TbRuleEngineQueueSubmitStrategyConfiguration; @Component @Slf4j public class TbRuleEngineSubmitStrategyFactory { - public TbRuleEngineSubmitStrategy newInstance(String name, TbRuleEngineQueueSubmitStrategyConfiguration configuration) { - switch (configuration.getType()) { - case "BURST": + public TbRuleEngineSubmitStrategy newInstance(String name, SubmitStrategy submitStrategy) { + switch (submitStrategy.getType()) { + case BURST: return new BurstTbRuleEngineSubmitStrategy(name); - case "BATCH": - return new BatchTbRuleEngineSubmitStrategy(name, configuration.getBatchSize()); - case "SEQUENTIAL_BY_ORIGINATOR": + case BATCH: + return new BatchTbRuleEngineSubmitStrategy(name, submitStrategy.getBatchSize()); + case SEQUENTIAL_BY_ORIGINATOR: return new SequentialByOriginatorIdTbRuleEngineSubmitStrategy(name); - case "SEQUENTIAL_BY_TENANT": + case SEQUENTIAL_BY_TENANT: return new SequentialByTenantIdTbRuleEngineSubmitStrategy(name); - case "SEQUENTIAL": + case SEQUENTIAL: return new SequentialTbRuleEngineSubmitStrategy(name); default: - throw new RuntimeException("TbRuleEngineProcessingStrategy with type " + configuration.getType() + " is not supported!"); + throw new RuntimeException("TbRuleEngineProcessingStrategy with type " + submitStrategy.getType() + " is not supported!"); } } diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index 6625bdefc7..157e10295c 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -69,6 +69,11 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; +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.security.Authority; import org.thingsboard.server.config.ThingsboardSecurityConfiguration; import org.thingsboard.server.dao.tenant.TenantProfileService; diff --git a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java index 09fe580661..0c13157623 100644 --- a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java @@ -26,14 +26,13 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.queue.TbQueueService; -import org.thingsboard.server.queue.discovery.HashPartitionService; import org.thingsboard.server.common.msg.queue.ServiceType; -import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.discovery.HashPartitionService; +import org.thingsboard.server.queue.discovery.QueueRoutingInfoService; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; -import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import java.util.ArrayList; import java.util.Collections; @@ -44,7 +43,6 @@ import java.util.Map; import java.util.stream.Collectors; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @Slf4j @RunWith(MockitoJUnitRunner.class) @@ -57,26 +55,20 @@ public class HashPartitionServiceTest { private TbServiceInfoProvider discoveryService; private TenantRoutingInfoService routingInfoService; private ApplicationEventPublisher applicationEventPublisher; - private TbQueueRuleEngineSettings ruleEngineSettings; - private TbQueueService queueService; + private QueueRoutingInfoService queueRoutingInfoService; private String hashFunctionName = "sha256"; - @Before public void setup() throws Exception { discoveryService = mock(TbServiceInfoProvider.class); applicationEventPublisher = mock(ApplicationEventPublisher.class); routingInfoService = mock(TenantRoutingInfoService.class); - ruleEngineSettings = mock(TbQueueRuleEngineSettings.class); - queueService = mock(TbQueueService.class); + queueRoutingInfoService = mock(QueueRoutingInfoService.class); clusterRoutingService = new HashPartitionService(discoveryService, routingInfoService, applicationEventPublisher, - ruleEngineSettings, - queueService - ); - when(ruleEngineSettings.getQueues()).thenReturn(Collections.emptyList()); + queueRoutingInfoService); ReflectionTestUtils.setField(clusterRoutingService, "coreTopic", "tb.core"); ReflectionTestUtils.setField(clusterRoutingService, "corePartitions", 10); ReflectionTestUtils.setField(clusterRoutingService, "hashFunctionName", hashFunctionName); diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 1084cb2e44..014244cb08 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -20,11 +20,11 @@ package transport; option java_package = "org.thingsboard.server.gen.transport"; option java_outer_classname = "TransportProtos"; -message QueueInfo { - string name = 1; - string topic = 2; - int32 partitions = 3; -} +//message QueueInfo { +// string name = 1; +// string topic = 2; +// int32 partitions = 3; +//} /** * Service Discovery Data Structures; @@ -34,7 +34,7 @@ message ServiceInfo { repeated string serviceTypes = 2; int64 tenantIdMSB = 3; int64 tenantIdLSB = 4; - repeated QueueInfo ruleEngineQueues = 5; +// repeated QueueInfo ruleEngineQueues = 5; repeated string transports = 6; } @@ -741,6 +741,8 @@ message ToCoreNotificationMsg { FromDeviceRPCResponseProto fromDeviceRpcResponse = 2; bytes componentLifecycleMsg = 3; bytes edgeEventUpdateMsg = 4; + QueueUpdateMsg queueUpdateMsg = 5; + QueueDeleteMsg queueDeleteMsg = 6; } /* Messages that are handled by ThingsBoard RuleEngine Service */ @@ -755,6 +757,8 @@ message ToRuleEngineMsg { message ToRuleEngineNotificationMsg { bytes componentLifecycleMsg = 1; FromDeviceRPCResponseProto fromDeviceRpcResponse = 2; + QueueUpdateMsg queueUpdateMsg = 3; + QueueDeleteMsg queueDeleteMsg = 4; } /* Messages that are handled by ThingsBoard Transport Service */ @@ -773,6 +777,8 @@ message ToTransportMsg { ResourceUpdateMsg resourceUpdateMsg = 12; ResourceDeleteMsg resourceDeleteMsg = 13; UplinkNotificationMsg uplinkNotificationMsg = 14; + QueueUpdateMsg queueUpdateMsg = 15; + QueueDeleteMsg queueDeleteMsg = 16; } message UsageStatsKVProto{ diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java index 5a0e540ac4..e372fb600c 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java @@ -29,7 +29,7 @@ import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; -@Service +//@Service @RequiredArgsConstructor public class DefaultTbQueueService implements TbQueueService { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java index 64ca3ccac5..62e9852dd1 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java @@ -25,10 +25,8 @@ import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.TbTransportService; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import org.thingsboard.server.queue.util.AfterContextReady; import javax.annotation.PostConstruct; @@ -95,16 +93,6 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { builder.setTenantIdMSB(tenantId.getMostSignificantBits()); builder.setTenantIdLSB(tenantId.getLeastSignificantBits()); - if (serviceTypes.contains(ServiceType.TB_RULE_ENGINE) && ruleEngineSettings != null) { - for (TbRuleEngineQueueConfiguration queue : ruleEngineSettings.getQueues()) { - TransportProtos.QueueInfo queueInfo = TransportProtos.QueueInfo.newBuilder() - .setName(queue.getName()) - .setTopic(queue.getTopic()) - .setPartitions(queue.getPartitions()).build(); - builder.addRuleEngineQueues(queueInfo); - } - } - serviceInfo = builder.build(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 4e27a01760..58ef13ac6d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -29,11 +29,9 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; -import org.thingsboard.server.queue.TbQueueService; import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; -import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import javax.annotation.PostConstruct; import java.util.ArrayList; @@ -63,10 +61,9 @@ public class HashPartitionService implements PartitionService { private final ApplicationEventPublisher applicationEventPublisher; private final TbServiceInfoProvider serviceInfoProvider; private final TenantRoutingInfoService tenantRoutingInfoService; - private final TbQueueRuleEngineSettings tbQueueRuleEngineSettings; - private final TbQueueService queueService; - private final ConcurrentMap partitionTopics = new ConcurrentHashMap<>(); - private final ConcurrentMap partitionSizes = new ConcurrentHashMap<>(); + private final QueueRoutingInfoService queueRoutingInfoService; + private final ConcurrentMap> partitionTopicsMap = new ConcurrentHashMap<>(); + private final ConcurrentMap> partitionSizesMap = new ConcurrentHashMap<>(); private final ConcurrentMap tenantRoutingInfoMap = new ConcurrentHashMap<>(); private ConcurrentMap> myPartitions = new ConcurrentHashMap<>(); @@ -80,26 +77,87 @@ public class HashPartitionService implements PartitionService { public HashPartitionService(TbServiceInfoProvider serviceInfoProvider, TenantRoutingInfoService tenantRoutingInfoService, ApplicationEventPublisher applicationEventPublisher, - TbQueueRuleEngineSettings tbQueueRuleEngineSettings, - TbQueueService queueService) { + QueueRoutingInfoService queueRoutingInfoService) { this.serviceInfoProvider = serviceInfoProvider; this.tenantRoutingInfoService = tenantRoutingInfoService; this.applicationEventPublisher = applicationEventPublisher; - this.tbQueueRuleEngineSettings = tbQueueRuleEngineSettings; - this.queueService = queueService; + this.queueRoutingInfoService = queueRoutingInfoService; } @PostConstruct public void init() { this.hashFunction = forName(hashFunctionName); - partitionSizes.put(new ServiceQueue(ServiceType.TB_CORE), corePartitions); - partitionTopics.put(new ServiceQueue(ServiceType.TB_CORE), coreTopic); - tbQueueRuleEngineSettings.getQueues().forEach(queueConfiguration -> { - partitionTopics.put(new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueConfiguration.getName()), queueConfiguration.getTopic()); - partitionSizes.put(new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueConfiguration.getName()), queueConfiguration.getPartitions()); + partitionsInit(); + } + + private void partitionsInit() { + addPartitionSizeToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE, "Main"), corePartitions); + addPartitionTopicToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE, "Main"), coreTopic); + + List queueRoutingInfoList; + + String serviceType = serviceInfoProvider.getServiceType(); + + if ("tb-rule-engine".equals(serviceType)) { + queueRoutingInfoList = queueRoutingInfoService.getQueuesRoutingInfo(serviceInfoProvider.getIsolatedTenant().orElse(TenantId.SYS_TENANT_ID)); + } else if ("monolith".equals(serviceType)) { + queueRoutingInfoList = queueRoutingInfoService.getAllQueuesRoutingInfo(); + } else if ("tb-core".equals(serviceType)) { + queueRoutingInfoList = queueRoutingInfoService.getMainQueuesRoutingInfo(); + } else { + //If transport started earlier than tb-core + int getQueuesRetries = 10; + while (true) { + if (getQueuesRetries > 0) { + log.info("Try to get queue routing info."); + try { + queueRoutingInfoList = queueRoutingInfoService.getMainQueuesRoutingInfo(); + break; + } catch (Exception e) { + log.info("Failed to get queues routing info!"); + getQueuesRetries--; + } + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + log.info("Failed to await queues routing info!", e); + } + } else { + throw new RuntimeException("Failed to await queues routing info!"); + } + } + } + + queueRoutingInfoList.forEach(queue -> { + addPartitionTopicToMap(queue.getTenantId(), new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getQueueName()), queue.getQueueTopic()); + addPartitionSizeToMap(queue.getTenantId(), new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getQueueName()), queue.getPartitions()); }); } + @Override + public void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { + TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); + addPartitionTopicToMap(tenantId, new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName()), queueUpdateMsg.getQueueTopic()); + addPartitionSizeToMap(tenantId, new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName()), queueUpdateMsg.getPartitions()); + } + + @Override + public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { + TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); + ServiceQueue serviceQueue = new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName()); + partitionTopicsMap.get(tenantId).remove(serviceQueue); + partitionSizesMap.get(tenantId).remove(serviceQueue); + myPartitions.remove(new ServiceQueueKey(serviceQueue, tenantId)); + } + + private void addPartitionSizeToMap(TenantId tenantId, ServiceQueue serviceQueue, int partitions) { + partitionSizesMap.computeIfAbsent(tenantId, id -> new ConcurrentHashMap<>()).put(serviceQueue, partitions); + } + + private void addPartitionTopicToMap(TenantId tenantId, ServiceQueue serviceQueue, String topic) { + partitionTopicsMap.computeIfAbsent(tenantId, id -> new ConcurrentHashMap<>()).put(serviceQueue, topic); + } + @Override public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) { return resolve(new ServiceQueue(serviceType), tenantId, entityId); @@ -107,23 +165,25 @@ public class HashPartitionService implements PartitionService { @Override public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) { - queueName = queueService.resolve(serviceType, queueName); - return resolve(new ServiceQueue(serviceType, queueName), tenantId, entityId); + ServiceQueue serviceQueue = new ServiceQueue(serviceType, queueName); + ConcurrentMap queues = partitionTopicsMap.get(getSystemIsolatedTenantId(serviceType, tenantId)); + + if (!queues.containsKey(serviceQueue)) { + serviceQueue = new ServiceQueue(serviceType); + } + + return resolve(serviceQueue, tenantId, entityId); } private TopicPartitionInfo resolve(ServiceQueue serviceQueue, TenantId tenantId, EntityId entityId) { int hash = hashFunction.newHasher() .putLong(entityId.getId().getMostSignificantBits()) .putLong(entityId.getId().getLeastSignificantBits()).hash().asInt(); - Integer partitionSize = partitionSizes.get(serviceQueue); - int partition; - if (partitionSize != null) { - partition = Math.abs(hash % partitionSize); - } else { - //TODO: In 2.6/3.1 this should not happen because all Rule Engine Queues will be in the DB and we always know their partition sizes. - partition = 0; - } - boolean isolatedTenant = isIsolated(serviceQueue, tenantId); + + boolean isolatedTenant = isIsolated(serviceQueue.getType(), tenantId); + Integer partitionSize = partitionSizesMap.get(isolatedTenant ? tenantId : TenantId.SYS_TENANT_ID).get(serviceQueue); + int partition = Math.abs(hash % partitionSize); + TopicPartitionInfoKey cacheKey = new TopicPartitionInfoKey(serviceQueue, isolatedTenant ? tenantId : null, partition); return tpiCache.computeIfAbsent(cacheKey, key -> buildTopicPartitionInfo(serviceQueue, tenantId, partition)); } @@ -143,7 +203,7 @@ public class HashPartitionService implements PartitionService { ConcurrentMap> oldPartitions = myPartitions; TenantId myIsolatedOrSystemTenantId = getSystemOrIsolatedTenantId(currentService); myPartitions = new ConcurrentHashMap<>(); - partitionSizes.forEach((serviceQueue, size) -> { + partitionSizesMap.get(myIsolatedOrSystemTenantId).forEach((serviceQueue, size) -> { ServiceQueueKey myServiceQueueKey = new ServiceQueueKey(serviceQueue, myIsolatedOrSystemTenantId); for (int i = 0; i < size; i++) { ServiceInfo serviceInfo = resolveByPartitionIdx(queueServicesMap.get(myServiceQueueKey), i); @@ -154,6 +214,8 @@ public class HashPartitionService implements PartitionService { } }); + tpiCache.clear(); + oldPartitions.forEach((serviceQueueKey, partitions) -> { if (!myPartitions.containsKey(serviceQueueKey)) { log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", serviceQueueKey); @@ -170,7 +232,6 @@ public class HashPartitionService implements PartitionService { applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceQueueKey, tpiList)); } }); - tpiCache.clear(); if (currentOtherServices == null) { currentOtherServices = new ArrayList<>(otherServices); @@ -196,21 +257,33 @@ public class HashPartitionService implements PartitionService { @Override public Set getAllServiceIds(ServiceType serviceType) { - Set result = new HashSet<>(); + return getAllServices(serviceType).stream().map(ServiceInfo::getServiceId).collect(Collectors.toSet()); + } + + @Override + public Set getAllServices(ServiceType serviceType) { + Set result = getOtherServices(serviceType); ServiceInfo current = serviceInfoProvider.getServiceInfo(); if (current.getServiceTypesList().contains(serviceType.name())) { - result.add(current.getServiceId()); + result.add(current); } + return result; + } + + @Override + public Set getOtherServices(ServiceType serviceType) { + Set result = new HashSet<>(); if (currentOtherServices != null) { for (ServiceInfo serviceInfo : currentOtherServices) { if (serviceInfo.getServiceTypesList().contains(serviceType.name())) { - result.add(serviceInfo.getServiceId()); + result.add(serviceInfo); } } } return result; } + @Override public int resolvePartitionIndex(UUID entityId, int partitions) { int hash = hashFunction.newHasher() @@ -231,10 +304,10 @@ public class HashPartitionService implements PartitionService { for (String serviceTypeStr : serviceInfo.getServiceTypesList()) { ServiceType serviceType = ServiceType.valueOf(serviceTypeStr.toUpperCase()); if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) { - for (TransportProtos.QueueInfo queue : serviceInfo.getRuleEngineQueuesList()) { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType, queue.getName()), getSystemOrIsolatedTenantId(serviceInfo)); - currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); - } +// for (TransportProtos.QueueInfo queue : serviceInfo.getRuleEngineQueuesList()) { +// ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType, queue.getName()), getSystemOrIsolatedTenantId(serviceInfo)); +// currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); +// } } else { ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType), getSystemOrIsolatedTenantId(serviceInfo)); currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); @@ -244,20 +317,18 @@ public class HashPartitionService implements PartitionService { return currentMap; } - private TopicPartitionInfo buildNotificationsTopicPartitionInfo(ServiceType serviceType, String serviceId) { - return new TopicPartitionInfo(serviceType.name().toLowerCase() + ".notifications." + serviceId, null, null, false); - } - private TopicPartitionInfo buildTopicPartitionInfo(ServiceQueueKey serviceQueueKey, int partition) { return buildTopicPartitionInfo(serviceQueueKey.getServiceQueue(), serviceQueueKey.getTenantId(), partition); } private TopicPartitionInfo buildTopicPartitionInfo(ServiceQueue serviceQueue, TenantId tenantId, int partition) { + boolean isolatedTenant = isIsolated(serviceQueue.getType(), tenantId); + TopicPartitionInfo.TopicPartitionInfoBuilder tpi = TopicPartitionInfo.builder(); - tpi.topic(partitionTopics.get(serviceQueue)); + tpi.topic(partitionTopicsMap.get(isolatedTenant ? tenantId : TenantId.SYS_TENANT_ID).get(serviceQueue)); tpi.partition(partition); ServiceQueueKey myPartitionsSearchKey; - if (isIsolated(serviceQueue, tenantId)) { + if (isolatedTenant) { tpi.tenantId(tenantId); myPartitionsSearchKey = new ServiceQueueKey(serviceQueue, tenantId); } else { @@ -272,7 +343,7 @@ public class HashPartitionService implements PartitionService { return tpi.build(); } - private boolean isIsolated(ServiceQueue serviceQueue, TenantId tenantId) { + private boolean isIsolated(ServiceType serviceType, TenantId tenantId) { if (TenantId.SYS_TENANT_ID.equals(tenantId)) { return false; } @@ -289,7 +360,7 @@ public class HashPartitionService implements PartitionService { if (routingInfo == null) { throw new RuntimeException("Tenant not found!"); } - switch (serviceQueue.getType()) { + switch (serviceType) { case TB_CORE: return routingInfo.isIsolatedTbCore(); case TB_RULE_ENGINE: @@ -299,6 +370,10 @@ public class HashPartitionService implements PartitionService { } } + private TenantId getSystemIsolatedTenantId(ServiceType serviceType, TenantId tenantId) { + return isIsolated(serviceType, tenantId) ? tenantId : TenantId.SYS_TENANT_ID; + } + private void logServiceInfo(TransportProtos.ServiceInfo server) { TenantId tenantId = getSystemOrIsolatedTenantId(server); if (tenantId.isNullUid()) { @@ -317,12 +392,12 @@ public class HashPartitionService implements PartitionService { for (String serviceTypeStr : instance.getServiceTypesList()) { ServiceType serviceType = ServiceType.valueOf(serviceTypeStr.toUpperCase()); if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) { - for (TransportProtos.QueueInfo queue : instance.getRuleEngineQueuesList()) { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType, queue.getName()), tenantId); - partitionSizes.put(new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getName()), queue.getPartitions()); - partitionTopics.put(new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getName()), queue.getTopic()); - queueServiceList.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(instance); - } + partitionTopicsMap.get(tenantId).forEach((serviceQueue, topic) -> { + if (serviceQueue.getType().equals(ServiceType.TB_RULE_ENGINE)) { + ServiceQueueKey serviceQueueKey = new ServiceQueueKey(serviceQueue, tenantId); + queueServiceList.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(instance); + } + }); } else { ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType), tenantId); queueServiceList.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(instance); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java index c222b252a5..84065ec283 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java @@ -49,7 +49,15 @@ public interface PartitionService { */ Set getAllServiceIds(ServiceType serviceType); + Set getAllServices(ServiceType serviceType); + + Set getOtherServices(ServiceType serviceType); + int resolvePartitionIndex(UUID entityId, int partitions); int countTransportsByType(String type); + + void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg); + + void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java index 2a691a2531..8e73c23c7e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java @@ -25,6 +25,8 @@ public interface TbServiceInfoProvider { String getServiceId(); + String getServiceType(); + ServiceInfo getServiceInfo(); boolean isService(ServiceType serviceType); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerStatsService.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerStatsService.java index e204025ec5..e62ee850fa 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerStatsService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerStatsService.java @@ -25,7 +25,9 @@ import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.consumer.OffsetAndMetadata; import org.apache.kafka.common.TopicPartition; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -55,7 +57,10 @@ public class TbKafkaConsumerStatsService { private final TbKafkaSettings kafkaSettings; private final TbKafkaConsumerStatisticConfig statsConfig; - private final PartitionService partitionService; + + @Lazy + @Autowired + private PartitionService partitionService; private AdminClient adminClient; private Consumer consumer; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java index 873719c832..660173c71d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; @@ -45,7 +46,6 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; @@ -124,7 +124,7 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java index 9c223f08f5..9d9fd29078 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -38,7 +39,6 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; @@ -112,7 +112,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index e3c81df1dd..53de7c1397 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -36,7 +37,6 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; @Slf4j @Component @@ -91,7 +91,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new InMemoryTbQueueConsumer<>(configuration.getTopic()); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index ce171497de..104c531e12 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; @@ -50,7 +51,6 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -156,7 +156,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { String queueName = configuration.getName(); TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java index 645cbee906..12a51fc8fd 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -47,7 +48,6 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -158,7 +158,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { String queueName = configuration.getName(); TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java index 3388f0d0f3..aceb9d4f0d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; @@ -50,7 +51,6 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -126,7 +126,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java index 8a3b88846f..bd9a360536 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -46,7 +47,6 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -116,7 +116,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java index a22f6811e3..2a724289bb 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; @@ -50,7 +51,6 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -124,7 +124,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java index 21e152787d..55737d7753 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -46,7 +47,6 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -115,7 +115,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java index da219d9084..88bb0a4045 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; @@ -49,7 +50,6 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -123,7 +123,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java index a6ef991f57..622a3cc1fd 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java @@ -19,6 +19,7 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; @@ -46,7 +47,6 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -115,7 +115,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact } @Override - public TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration) { + public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, configuration.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java index df64b768ab..07148ee924 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.queue.provider; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; @@ -26,7 +27,6 @@ import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.TbQueueRequestTemplate; import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; /** * Responsible for initialization of various Producers and Consumers used by TB Core Node. @@ -83,7 +83,7 @@ public interface TbRuleEngineQueueFactory extends TbUsageStatsClientQueueFactory * @param configuration */ //TODO 2.5 ybondarenko: make sure you use queueName to distinct consumers where necessary - TbQueueConsumer> createToRuleEngineMsgConsumer(TbRuleEngineQueueConfiguration configuration); + TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration); /** * Used to consume high priority messages by TB Core Service diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java index 6d8e3c5b0b..60867f314f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java @@ -17,7 +17,9 @@ package org.thingsboard.server.queue.usagestats; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.EntityType; @@ -57,7 +59,9 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { private final EnumMap> stats = new EnumMap<>(ApiUsageRecordKey.class); - private final PartitionService partitionService; + @Lazy + @Autowired + private PartitionService partitionService; private final SchedulerComponent scheduler; private final TbQueueProducerProvider producerProvider; private TbQueueProducer> msgProducer; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 3de2a6a7d5..f06a7f76ea 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -22,8 +22,10 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.protobuf.ByteString; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardExecutors; @@ -152,18 +154,25 @@ public class DefaultTransportService implements TransportService { @Value("${transport.stats.enabled:false}") private boolean statsEnabled; + @Autowired + @Lazy + private TbApiUsageClient apiUsageClient; + @Autowired + @Lazy + private PartitionService partitionService; + private final Map statsMap = new LinkedHashMap<>(); private final Gson gson = new Gson(); private final TbTransportQueueFactory queueProvider; private final TbQueueProducerProvider producerProvider; - private final PartitionService partitionService; + private final NotificationsTopicService notificationsTopicService; private final TbServiceInfoProvider serviceInfoProvider; private final StatsFactory statsFactory; private final TransportDeviceProfileCache deviceProfileCache; private final TransportTenantProfileCache tenantProfileCache; - private final TbApiUsageClient apiUsageClient; + private final TransportRateLimitService rateLimitService; private final DataDecodingEncodingService dataDecodingEncodingService; private final SchedulerComponent scheduler; @@ -191,23 +200,20 @@ public class DefaultTransportService implements TransportService { public DefaultTransportService(TbServiceInfoProvider serviceInfoProvider, TbTransportQueueFactory queueProvider, TbQueueProducerProvider producerProvider, - PartitionService partitionService, NotificationsTopicService notificationsTopicService, StatsFactory statsFactory, TransportDeviceProfileCache deviceProfileCache, TransportTenantProfileCache tenantProfileCache, - TbApiUsageClient apiUsageClient, TransportRateLimitService rateLimitService, + TransportRateLimitService rateLimitService, DataDecodingEncodingService dataDecodingEncodingService, SchedulerComponent scheduler, TransportResourceCache transportResourceCache, ApplicationEventPublisher eventPublisher) { this.serviceInfoProvider = serviceInfoProvider; this.queueProvider = queueProvider; this.producerProvider = producerProvider; - this.partitionService = partitionService; this.notificationsTopicService = notificationsTopicService; this.statsFactory = statsFactory; this.deviceProfileCache = deviceProfileCache; this.tenantProfileCache = tenantProfileCache; - this.apiUsageClient = apiUsageClient; this.rateLimitService = rateLimitService; this.dataDecodingEncodingService = dataDecodingEncodingService; this.scheduler = scheduler; @@ -983,6 +989,10 @@ public class DefaultTransportService implements TransportService { log.warn("ResourceDelete - [{}] [{}]", id, mdRez); transportCallbackExecutor.submit(() -> mdRez.getListener().onResourceDelete(msg)); }); + } else if (toSessionMsg.hasQueueUpdateMsg()) { + partitionService.updateQueue(toSessionMsg.getQueueUpdateMsg()); + } else if (toSessionMsg.hasQueueDeleteMsg()) { + partitionService.removeQueue(toSessionMsg.getQueueDeleteMsg()); } else { //TODO: should we notify the device actor about missed session? log.debug("[{}] Missing session.", sessionId); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java index bcdc07b5b0..537a86b1d6 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java @@ -36,13 +36,9 @@ import java.util.stream.Collectors; @ConditionalOnExpression("'${service.type:null}'=='tb-transport'") public class TransportQueueRoutingInfoService implements QueueRoutingInfoService { - private TransportService transportService; - @Lazy @Autowired - public void setTransportService(TransportService transportService) { - this.transportService = transportService; - } + private TransportService transportService; @Override public List getAllQueuesRoutingInfo() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 35d4dc2899..7d6412cbea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -29,7 +29,6 @@ import com.squareup.wire.schema.internal.parser.ProtoParser; import com.squareup.wire.schema.internal.parser.TypeElement; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.util.SecurityUtil; -import org.thingsboard.server.common.data.StringUtils; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; @@ -45,6 +44,7 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; @@ -61,28 +61,28 @@ import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransp import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; -import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.RPKLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.X509LwM2MBootstrapServerCredential; -import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.msg.EncryptionUtil; -import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TenantDao; -import org.thingsboard.server.queue.TbQueueService; import java.util.Arrays; import java.util.Collections; @@ -115,7 +115,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D } @Autowired(required = false) - private TbQueueService queueService; + private QueueService queueService; @Autowired private DeviceProfileDao deviceProfileDao; @@ -386,8 +386,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D throw new DataValidationException("Another default device profile is present in scope of current tenant!"); } } - if (!StringUtils.isEmpty(deviceProfile.getDefaultQueueName()) && queueService != null){ - if(!queueService.getQueuesByServiceType(ServiceType.TB_RULE_ENGINE).contains(deviceProfile.getDefaultQueueName())){ + if (!StringUtils.isEmpty(deviceProfile.getDefaultQueueName()) && queueService != null) { + //TODO: Yevhen replace queue name to queue id + if (!queueService.findQueuesByTenantId(tenantId) + .stream() + .map(Queue::getName) + .collect(Collectors.toSet()) + .contains(deviceProfile.getDefaultQueueName())) { throw new DataValidationException("Device profile is referencing to non-existent queue!"); } } @@ -748,7 +753,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D case PSK: break; case RPK: - RPKLwM2MBootstrapServerCredential rpkServerCredentials = (RPKLwM2MBootstrapServerCredential) bootstrapServerConfig; + RPKLwM2MBootstrapServerCredential rpkServerCredentials = (RPKLwM2MBootstrapServerCredential) bootstrapServerConfig; server = rpkServerCredentials.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; if (StringUtils.isEmpty(rpkServerCredentials.getServerPublicKey())) { throw new DeviceCredentialsValidationException(server + " RPK public key must be specified!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index 7049d8ae1c..e2fd459189 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.queue; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -64,7 +65,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ // private QueueStatsService queueStatsService; @Override - @Transactional public Queue saveQueue(Queue queue) { log.trace("Executing createOrUpdateQueue [{}]", queue); queueValidator.validate(queue, Queue::getTenantId); @@ -75,9 +75,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ savedQueue = updateQueue(queue); } -// if (queueClusterService != null) { -// queueClusterService.onQueueChange(savedQueue, null); -// } return savedQueue; } @@ -88,6 +85,11 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } } + + if (queueClusterService != null) { + queueClusterService.onQueueChange(createdQueue, null); + } + return createdQueue; } @@ -98,32 +100,39 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ int oldPartitions = oldQueue.getPartitions(); int currentPartitions = queue.getPartitions(); - //TODO: remove if partitions can't be deleted. if (currentPartitions != oldPartitions && tbQueueAdmin != null) { - queueClusterService.onQueueDelete(queue, null); if (currentPartitions > oldPartitions) { log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); for (int i = oldPartitions; i < currentPartitions; i++) { tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } + if (queueClusterService != null) { + queueClusterService.onQueueChange(updatedQueue, null); + } } else { log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); + if (queueClusterService != null) { + queueClusterService.onQueueChange(updatedQueue, null); + } + await(); for (int i = currentPartitions; i < oldPartitions; i++) { tbQueueAdmin.deleteTopic(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } } + } else if (!oldQueue.equals(queue) && queueClusterService != null) { + queueClusterService.onQueueChange(updatedQueue, null); } return updatedQueue; } @Override - @Transactional public void deleteQueue(TenantId tenantId, QueueId queueId) { log.trace("Executing deleteQueue, queueId: [{}]", queueId); Queue queue = findQueueById(tenantId, queueId); if (queueClusterService != null) { queueClusterService.onQueueDelete(queue, null); + await(); } // queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); boolean result = queueDao.removeById(tenantId, queueId.getId()); @@ -140,6 +149,11 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ } } + @SneakyThrows + private void await() { + Thread.sleep(3000); + } + @Override public List findQueuesByTenantId(TenantId tenantId) { log.trace("Executing findQueues, tenantId: [{}]", tenantId); diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index ed69fd9b72..82fbaeed74 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -147,6 +147,8 @@ services: - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-mqtt-transport2: restart: always image: "${DOCKER_REPO}/${MQTT_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" @@ -161,6 +163,8 @@ services: - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-http-transport1: restart: always image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" @@ -175,6 +179,8 @@ services: - ./tb-transports/http/log:/var/log/tb-http-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-http-transport2: restart: always image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" @@ -189,6 +195,8 @@ services: - ./tb-transports/http/log:/var/log/tb-http-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-coap-transport: restart: always image: "${DOCKER_REPO}/${COAP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" @@ -203,6 +211,8 @@ services: - ./tb-transports/coap/log:/var/log/tb-coap-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-lwm2m-transport: restart: always image: "${DOCKER_REPO}/${LWM2M_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" @@ -217,6 +227,8 @@ services: - ./tb-transports/lwm2m/log:/var/log/tb-lwm2m-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-snmp-transport: restart: always image: "${DOCKER_REPO}/${SNMP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" @@ -229,6 +241,8 @@ services: - ./tb-transports/snmp/log:/var/log/tb-snmp-transport depends_on: - zookeeper + - tb-core1 + - tb-core2 tb-web-ui1: restart: always image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}" diff --git a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html index 6abd58dda9..29de0f2f12 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html +++ b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html @@ -16,7 +16,7 @@ --> - {{ 'queue.name' | translate }} + {{ 'queue.queue-name' | translate }} Date: Wed, 13 Apr 2022 21:55:03 +0200 Subject: [PATCH 10/58] used queueId instead of queueName in DeviceProfile and TbMsg --- .../server/actors/ActorSystemContext.java | 11 +- .../actors/ruleChain/DefaultTbContext.java | 71 +++--- .../RuleChainActorMessageProcessor.java | 2 +- .../rpc/processor/TelemetryEdgeProcessor.java | 33 ++- .../queue/DefaultQueueRoutingInfoService.java | 10 - .../queue/DefaultTbClusterService.java | 15 +- .../DefaultTbRuleEngineConsumerService.java | 11 +- .../TbRuleEngineProcessingResult.java | 7 +- ...TbRuleEngineProcessingStrategyFactory.java | 7 +- .../transport/DefaultTransportApiService.java | 15 +- common/cluster-api/src/main/proto/queue.proto | 32 ++- .../server/common/data/DeviceProfile.java | 5 +- .../server/common/data/id/QueueId.java | 2 - .../thingsboard/server/common/msg/TbMsg.java | 63 +++-- .../queue/discovery/HashPartitionService.java | 36 +-- .../queue/discovery/PartitionService.java | 3 +- .../queue/discovery/QueueRoutingInfo.java | 11 +- .../discovery/QueueRoutingInfoService.java | 5 - .../common/transport/TransportService.java | 4 - .../service/DefaultTransportService.java | 37 +-- .../TransportQueueRoutingInfoService.java | 15 -- .../dao/device/DeviceProfileServiceImpl.java | 12 +- .../server/dao/model/ModelConstants.java | 2 +- .../dao/model/sql/DeviceProfileEntity.java | 13 +- .../main/resources/sql/schema-entities.sql | 31 +-- dao/src/test/resources/sql/system-data.sql | 6 + .../rule/engine/api/TbContext.java | 14 +- .../TbCopyAttributesToEntityViewNode.java | 2 +- .../rule/engine/action/TbMsgCountNode.java | 4 +- .../rule/engine/debug/TbMsgGeneratorNode.java | 6 +- .../rule/engine/delay/TbMsgDelayNode.java | 2 +- .../rule/engine/flow/TbCheckpointNode.java | 12 +- .../flow/TbCheckpointNodeConfiguration.java | 3 + .../rule/engine/profile/AlarmState.java | 8 +- .../rule/engine/rpc/TbSendRPCRequestNode.java | 4 +- .../profile/TbDeviceProfileNodeTest.java | 30 +-- ui-ngx/src/app/core/http/entity.service.ts | 15 +- ui-ngx/src/app/core/http/queue.service.ts | 4 +- .../add-device-profile-dialog.component.html | 6 +- .../add-device-profile-dialog.component.ts | 8 +- .../profile/device-profile.component.html | 6 +- .../profile/device-profile.component.ts | 8 +- .../device-wizard-dialog.component.html | 6 +- .../device-wizard-dialog.component.scss | 2 +- .../wizard/device-wizard-dialog.component.ts | 11 +- .../queue/queue-autocomplete.component.html | 54 +++++ .../queue/queue-autocomplete.component.ts | 215 ++++++++++++++++++ ui-ngx/src/app/shared/models/device.models.ts | 3 +- ui-ngx/src/app/shared/shared.module.ts | 3 + .../assets/locale/locale.constant-en_US.json | 2 +- 50 files changed, 561 insertions(+), 326 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html create mode 100644 ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 889bd616fc..bd78631aa7 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -40,6 +40,7 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbActorMsg; @@ -63,6 +64,7 @@ import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.nosql.CassandraBufferedRateReadExecutor; import org.thingsboard.server.dao.nosql.CassandraBufferedRateWriteExecutor; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -330,6 +332,11 @@ public class ActorSystemContext { @Getter private TbRpcService tbRpcService; + @Lazy + @Autowired(required = false) + @Getter + private QueueService queueService; + @Value("${actors.session.max_concurrent_sessions_per_device:1}") @Getter private long maxConcurrentSessionsPerDevice; @@ -495,8 +502,8 @@ public class ActorSystemContext { return partitionService.resolve(serviceType, tenantId, entityId); } - public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) { - return partitionService.resolve(serviceType, queueName, tenantId, entityId); + public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) { + return partitionService.resolve(serviceType, queueId, tenantId, entityId); } public String getServiceId() { diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 66fe935d68..ee3f5e15ac 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; @@ -57,7 +58,6 @@ import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgProcessingStackItem; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.asset.AssetService; @@ -72,6 +72,7 @@ import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.nosql.CassandraStatementTask; import org.thingsboard.server.dao.nosql.TbResultSetFuture; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -161,8 +162,8 @@ class DefaultTbContext implements TbContext { } @Override - public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer onFailure) { - TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName); + public void enqueue(TbMsg tbMsg, QueueId queueId, Runnable onSuccess, Consumer onFailure) { + TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId); enqueue(tpi, tbMsg, onFailure, onSuccess); } @@ -213,33 +214,30 @@ class DefaultTbContext implements TbContext { } @Override - public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer onFailure) { - TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName); - enqueueForTellNext(tpi, queueName, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure); + public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, String relationType, Runnable onSuccess, Consumer onFailure) { + TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId); + enqueueForTellNext(tpi, queueId, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure); } @Override - public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set relationTypes, Runnable onSuccess, Consumer onFailure) { - TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName); - enqueueForTellNext(tpi, queueName, tbMsg, relationTypes, null, onSuccess, onFailure); + public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, Set relationTypes, Runnable onSuccess, Consumer onFailure) { + TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId); + enqueueForTellNext(tpi, queueId, tbMsg, relationTypes, null, onSuccess, onFailure); } - private TopicPartitionInfo resolvePartition(TbMsg tbMsg, String queueName) { - if (StringUtils.isEmpty(queueName)) { - queueName = ServiceQueue.MAIN; - } - return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator()); + private TopicPartitionInfo resolvePartition(TbMsg tbMsg, QueueId queueId) { + return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueId, getTenantId(), tbMsg.getOriginator()); } private TopicPartitionInfo resolvePartition(TbMsg tbMsg) { - return resolvePartition(tbMsg, tbMsg.getQueueName()); + return resolvePartition(tbMsg, tbMsg.getQueueId()); } private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) { - enqueueForTellNext(tpi, source.getQueueName(), source, relationTypes, failureMessage, onSuccess, onFailure); + enqueueForTellNext(tpi, source.getQueueId(), source, relationTypes, failureMessage, onSuccess, onFailure); } - private void enqueueForTellNext(TopicPartitionInfo tpi, String queueName, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) { + private void enqueueForTellNext(TopicPartitionInfo tpi, QueueId queueId, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) { if (!source.isValid()) { log.trace("[{}] Skip invalid message: {}", getTenantId(), source); onFailure.accept(new IllegalArgumentException("Source message is no longer valid!")); @@ -247,7 +245,7 @@ class DefaultTbContext implements TbContext { } RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId(); RuleNodeId ruleNodeId = nodeCtx.getSelf().getId(); - TbMsg tbMsg = TbMsg.newMsg(source, queueName, ruleChainId, ruleNodeId); + TbMsg tbMsg = TbMsg.newMsg(source, queueId, ruleChainId, ruleNodeId); TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder() .setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) @@ -306,13 +304,13 @@ class DefaultTbContext implements TbContext { } @Override - public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(queueName, type, originator, null, metaData, data); + public TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data) { + return newMsg(queueId, type, originator, null, metaData, data); } @Override - public TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); + public TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { + return TbMsg.newMsg(queueId, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); } @Override @@ -326,20 +324,17 @@ class DefaultTbContext implements TbContext { public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { RuleChainId ruleChainId = null; - String queueName = ServiceQueue.MAIN; + QueueId queueId = null; if (device.getDeviceProfileId() != null) { DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId()); if (deviceProfile == null) { log.warn("[{}] Device profile is null!", device.getDeviceProfileId()); - ruleChainId = null; - queueName = ServiceQueue.MAIN; } else { ruleChainId = deviceProfile.getDefaultRuleChainId(); - String defaultQueueName = deviceProfile.getDefaultQueueName(); - queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN; + queueId = deviceProfile.getDefaultQueueId(); } } - return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueName, ruleChainId); + return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueId, ruleChainId); } public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { @@ -348,21 +343,18 @@ class DefaultTbContext implements TbContext { public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) { RuleChainId ruleChainId = null; - String queueName = ServiceQueue.MAIN; + QueueId queueId = null; if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) { DeviceId deviceId = new DeviceId(alarm.getOriginator().getId()); DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); if (deviceProfile == null) { log.warn("[{}] Device profile is null!", deviceId); - ruleChainId = null; - queueName = ServiceQueue.MAIN; } else { ruleChainId = deviceProfile.getDefaultRuleChainId(); - String defaultQueueName = deviceProfile.getDefaultQueueName(); - queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN; + queueId = deviceProfile.getDefaultQueueId(); } } - return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueName, ruleChainId); + return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueId, ruleChainId); } @Override @@ -371,12 +363,12 @@ class DefaultTbContext implements TbContext { } public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action) { - return entityActionMsg(entity, id, ruleNodeId, action, ServiceQueue.MAIN, null); + return entityActionMsg(entity, id, ruleNodeId, action, null, null); } - public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, String queueName, RuleChainId ruleChainId) { + public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, QueueId queueId, RuleChainId ruleChainId) { try { - return TbMsg.newMsg(queueName, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null); + return TbMsg.newMsg(queueId, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null); } catch (JsonProcessingException | IllegalArgumentException e) { throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + e); } @@ -548,6 +540,11 @@ class DefaultTbContext implements TbContext { return mainCtx.getEdgeEventService(); } + @Override + public QueueService getQueueService() { + return mainCtx.getQueueService(); + } + @Override public EventLoopGroup getSharedEventLoop() { return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java index b4911650f3..add500f058 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java @@ -293,7 +293,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor ruleNodeRelations = nodeRoutes.get(originatorNodeId); if (ruleNodeRelations == null) { // When unchecked, this will cause NullPointerException when rule node doesn't exist anymore diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java index 9a9b568a23..9a08962e12 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; @@ -51,7 +52,6 @@ import org.thingsboard.server.common.data.kv.AttributeKey; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.util.JsonUtils; @@ -134,24 +134,23 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { return metaData; } - private Pair getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) { + private Pair getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) { if (EntityType.DEVICE.equals(entityId.getEntityType())) { DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())); RuleChainId ruleChainId; - String queueName; + QueueId queueId; if (deviceProfile == null) { log.warn("[{}] Device profile is null!", entityId); ruleChainId = null; - queueName = ServiceQueue.MAIN; + queueId = null; } else { ruleChainId = deviceProfile.getDefaultRuleChainId(); - String defaultQueueName = deviceProfile.getDefaultQueueName(); - queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN; + queueId = deviceProfile.getDefaultQueueId(); } - return new ImmutablePair<>(queueName, ruleChainId); + return new ImmutablePair<>(queueId, ruleChainId); } else { - return new ImmutablePair<>(ServiceQueue.MAIN, null); + return new ImmutablePair<>(null, null); } } @@ -160,10 +159,10 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); metaData.putValue("ts", tsKv.getTs() + ""); - Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - String queueName = defaultQueueAndRuleChain.getKey(); + Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); + QueueId queueId = defaultQueueAndRuleChain.getKey(); RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); - TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null); + 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() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { @@ -183,10 +182,10 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { private ListenableFuture processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { SettableFuture futureToSet = SettableFuture.create(); JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); - Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - String queueName = defaultQueueAndRuleChain.getKey(); + Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); + QueueId queueId = defaultQueueAndRuleChain.getKey(); RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); - TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null); + 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() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { @@ -210,10 +209,10 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor { Futures.addCallback(future, new FutureCallback>() { @Override public void onSuccess(@Nullable List voids) { - Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - String queueName = defaultQueueAndRuleChain.getKey(); + Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); + QueueId queueId = defaultQueueAndRuleChain.getKey(); RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); - TbMsg tbMsg = TbMsg.newMsg(queueName, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null); + TbMsg tbMsg = TbMsg.newMsg(queueId, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null); tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java index df22d42e62..d7a333a090 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultQueueRoutingInfoService.java @@ -18,7 +18,6 @@ package org.thingsboard.server.service.queue; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.queue.discovery.QueueRoutingInfo; import org.thingsboard.server.queue.discovery.QueueRoutingInfoService; @@ -42,13 +41,4 @@ public class DefaultQueueRoutingInfoService implements QueueRoutingInfoService { return queueService.findAllQueues().stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); } - @Override - public List getMainQueuesRoutingInfo() { - return queueService.findAllMainQueues().stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); - } - - @Override - public List getQueuesRoutingInfo(TenantId tenantId) { - return queueService.findQueuesByTenantId(tenantId).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 8f1db53764..102dcbc32c 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.data.ApiUsageState; @@ -169,7 +170,7 @@ public class DefaultTbClusterService implements TbClusterService { tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId()))); } } - TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId); + TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueId(), tenantId, entityId); log.trace("PUSHING msg: {} to:{}", tbMsg, tpi); ToRuleEngineMsg msg = ToRuleEngineMsg.newBuilder() .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) @@ -182,16 +183,16 @@ public class DefaultTbClusterService implements TbClusterService { private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) { if (deviceProfile != null) { RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId(); - String targetQueueName = deviceProfile.getDefaultQueueName(); + QueueId targetQueueId = deviceProfile.getDefaultQueueId(); boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId()); - boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName()); + boolean isQueueTransform = targetQueueId != null && !targetQueueId.equals(tbMsg.getQueueId()); if (isRuleChainTransform && isQueueTransform) { - tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName); + tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueId); } else if (isRuleChainTransform) { tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId); } else if (isQueueTransform) { - tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName); + tbMsg = TbMsg.transformMsg(tbMsg, targetQueueId); } } return tbMsg; @@ -495,6 +496,8 @@ public class DefaultTbClusterService implements TbClusterService { TransportProtos.QueueUpdateMsg queueUpdateMsg = TransportProtos.QueueUpdateMsg.newBuilder() .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) + .setQueueIdMSB(queue.getId().getId().getMostSignificantBits()) + .setQueueIdLSB(queue.getId().getId().getLeastSignificantBits()) .setQueueName(queue.getName()) .setQueueTopic(queue.getTopic()) .setPartitions(queue.getPartitions()) @@ -537,6 +540,8 @@ public class DefaultTbClusterService implements TbClusterService { TransportProtos.QueueDeleteMsg queueDeleteMsg = TransportProtos.QueueDeleteMsg.newBuilder() .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) + .setQueueIdMSB(queue.getId().getId().getMostSignificantBits()) + .setQueueIdLSB(queue.getId().getId().getLeastSignificantBits()) .setQueueName(queue.getName()) .build(); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 44cf8b19a6..4f5974457a 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -22,6 +22,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.ActorSystemContext; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rpc.RpcError; @@ -275,7 +276,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< final boolean timeout = !ctx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); - TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, ctx); + TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getId(), timeout, ctx); if (timeout) { printFirstOrAll(configuration, ctx, ctx.getPendingMap(), "Timeout"); } @@ -340,7 +341,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< new TbMsgPackCallback(id, tenantId, ctx); try { if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) { - forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback); + forwardToRuleEngineActor(configuration.getId(), tenantId, toRuleEngineMsg, callback); } else { callback.onSuccess(); } @@ -354,7 +355,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< log.info("{} to process [{}] messages", prefix, map.size()); for (Map.Entry> pending : map.entrySet()) { ToRuleEngineMsg tmp = pending.getValue().getValue(); - TbMsg tmpMsg = TbMsg.fromBytes(configuration.getName(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); + TbMsg tmpMsg = TbMsg.fromBytes(configuration.getId(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); RuleNodeInfo ruleNodeInfo = ctx.getLastVisitedRuleNode(pending.getKey()); if (printAll) { log.trace("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); @@ -454,8 +455,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< partitionService.removeQueue(queueDeleteMsg); } - private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { - TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback); + private void forwardToRuleEngineActor(QueueId queueId, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { + TbMsg tbMsg = TbMsg.fromBytes(queueId, toRuleEngineMsg.getTbMsg().toByteArray(), callback); QueueToRuleEngineMsg msg; ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); Set relationTypes = null; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java index 895de2412c..2e3fedb766 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java @@ -16,6 +16,7 @@ package org.thingsboard.server.service.queue.processing; import lombok.Getter; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; @@ -28,7 +29,7 @@ import java.util.concurrent.ConcurrentMap; public class TbRuleEngineProcessingResult { @Getter - private final String queueName; + private final QueueId queueId; @Getter private final boolean success; @Getter @@ -36,8 +37,8 @@ public class TbRuleEngineProcessingResult { @Getter private final TbMsgPackProcessingContext ctx; - public TbRuleEngineProcessingResult(String queueName, boolean timeout, TbMsgPackProcessingContext ctx) { - this.queueName = queueName; + public TbRuleEngineProcessingResult(QueueId queueId, boolean timeout, TbMsgPackProcessingContext ctx) { + this.queueId = queueId; this.timeout = timeout; this.ctx = ctx; this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty(); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java index 3056e65c78..2191c38017 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java @@ -23,7 +23,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueAckStrategyConfiguration; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -126,7 +125,7 @@ public class TbRuleEngineProcessingStrategyFactory { } log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size()); if (log.isTraceEnabled()) { - toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); + toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); } if (pauseBetweenRetries > 0) { try { @@ -165,10 +164,10 @@ public class TbRuleEngineProcessingStrategyFactory { log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size()); } if (log.isTraceEnabled()) { - result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); + result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); } if (log.isTraceEnabled()) { - result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); + result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); } return new TbRuleEngineProcessingDecision(true, null); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 0cba1ec325..ca5a978426 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -180,10 +180,6 @@ public class DefaultTransportApiService implements TransportApiService { result = handle(transportApiRequestMsg.getDeviceCredentialsRequestMsg()); } else if (transportApiRequestMsg.hasOtaPackageRequestMsg()) { result = handle(transportApiRequestMsg.getOtaPackageRequestMsg()); - } else if (transportApiRequestMsg.hasGetAllMainQueueRoutingInfoRequestMsg()) { - return Futures.transform(handle(transportApiRequestMsg.getGetAllMainQueueRoutingInfoRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); - } else if (transportApiRequestMsg.hasGetTenantQueueRoutingInfoRequestMsg()) { - return Futures.transform(handle(transportApiRequestMsg.getGetTenantQueueRoutingInfoRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); } else if (transportApiRequestMsg.hasGetAllQueueRoutingInfoRequestMsg()) { return Futures.transform(handle(transportApiRequestMsg.getGetAllQueueRoutingInfoRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); } @@ -646,25 +642,18 @@ public class DefaultTransportApiService implements TransportApiService { } } - private ListenableFuture handle(TransportProtos.GetAllMainQueueRoutingInfoRequestMsg requestMsg) { - return queuesToTransportApiResponseMsg(queueService.findAllMainQueues()); - } - private ListenableFuture handle(TransportProtos.GetAllQueueRoutingInfoRequestMsg requestMsg) { return queuesToTransportApiResponseMsg(queueService.findAllQueues()); } - private ListenableFuture handle(TransportProtos.GetTenantQueueRoutingInfoRequestMsg requestMsg) { - TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); - return queuesToTransportApiResponseMsg(queueService.findQueuesByTenantId(tenantId)); - } - private ListenableFuture queuesToTransportApiResponseMsg(List queues) { return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() .addAllGetQueueRoutingInfoResponseMsgs(queues.stream() .map(queue -> TransportProtos.GetQueueRoutingInfoResponseMsg.newBuilder() .setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) .setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) + .setQueueIdMSB(queue.getId().getId().getMostSignificantBits()) + .setQueueIdLSB(queue.getId().getId().getLeastSignificantBits()) .setQueueName(queue.getName()) .setQueueTopic(queue.getTopic()) .setPartitions(queue.getPartitions()) diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 014244cb08..8b4164e30f 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -197,37 +197,35 @@ message GetEntityProfileRequestMsg { int64 entityIdLSB = 3; } -message GetAllMainQueueRoutingInfoRequestMsg { -} - message GetAllQueueRoutingInfoRequestMsg { } -message GetTenantQueueRoutingInfoRequestMsg { - int64 tenantIdMSB = 1; - int64 tenantIdLSB = 2; -} - message GetQueueRoutingInfoResponseMsg { int64 tenantIdMSB = 1; int64 tenantIdLSB = 2; - string queueName = 3; - string queueTopic = 4; - int32 partitions = 5; + int64 queueIdMSB = 3; + int64 queueIdLSB = 4; + string queueName = 5; + string queueTopic = 6; + int32 partitions = 7; } message QueueUpdateMsg { int64 tenantIdMSB = 1; int64 tenantIdLSB = 2; - string queueName = 3; - string queueTopic = 4; - int32 partitions = 5; + int64 queueIdMSB = 3; + int64 queueIdLSB = 4; + string queueName = 5; + string queueTopic = 6; + int32 partitions = 7; } message QueueDeleteMsg { int64 tenantIdMSB = 1; int64 tenantIdLSB = 2; - string queueName = 3; + int64 queueIdMSB = 3; + int64 queueIdLSB = 4; + string queueName = 5; } message LwM2MRegistrationRequestMsg { @@ -706,9 +704,7 @@ message TransportApiRequestMsg { GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11; GetDeviceRequestMsg deviceRequestMsg = 12; GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13; - GetAllMainQueueRoutingInfoRequestMsg GetAllMainQueueRoutingInfoRequestMsg = 14; - GetTenantQueueRoutingInfoRequestMsg getTenantQueueRoutingInfoRequestMsg = 15; - GetAllQueueRoutingInfoRequestMsg getAllQueueRoutingInfoRequestMsg = 16; + GetAllQueueRoutingInfoRequestMsg getAllQueueRoutingInfoRequestMsg = 14; } /* Response from ThingsBoard Core Service to Transport Service */ diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 1dd6a2ad19..36cbda47c3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.Length; @@ -76,7 +77,7 @@ public class DeviceProfile extends SearchTextBased implements H @ApiModelProperty(position = 8, value = "Reference to the rule engine queue. " + "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.") - private String defaultQueueName; + private QueueId defaultQueueId; @Valid private transient DeviceProfileData profileData; @JsonIgnore @@ -107,7 +108,7 @@ public class DeviceProfile extends SearchTextBased implements H this.isDefault = deviceProfile.isDefault(); this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId(); this.defaultDashboardId = deviceProfile.getDefaultDashboardId(); - this.defaultQueueName = deviceProfile.getDefaultQueueName(); + this.defaultQueueId = deviceProfile.getDefaultQueueId(); this.setProfileData(deviceProfile.getProfileData()); this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); this.firmwareId = deviceProfile.getFirmwareId(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java index 37a4136d46..c0c4a3cde2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java @@ -16,7 +16,6 @@ package org.thingsboard.server.common.data.id; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import org.thingsboard.server.common.data.EntityType; @@ -35,7 +34,6 @@ public class QueueId extends UUIDBased implements EntityId { return new QueueId(UUID.fromString(queueId)); } - @JsonIgnore @Override public EntityType getEntityType() { return EntityType.QUEUE; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 879c10ed5e..bb3be80629 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -27,15 +27,14 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.msg.gen.MsgProtos; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import java.io.Serializable; import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; /** * Created by ashvayka on 13.01.18. @@ -44,7 +43,7 @@ import java.util.concurrent.atomic.AtomicInteger; @Slf4j public final class TbMsg implements Serializable { - private final String queueName; + private final QueueId queueId; private final UUID id; private final long ts; private final String type; @@ -68,12 +67,12 @@ public final class TbMsg implements Serializable { return ctx.getAndIncrementRuleNodeCounter(); } - public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId); + public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + return newMsg(queueId, type, originator, null, metaData, data, ruleChainId, ruleNodeId); } - public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + public static TbMsg newMsg(QueueId queueId, 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, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } @@ -82,23 +81,23 @@ public final class TbMsg implements Serializable { } public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } // REALLY NEW MSG - public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return newMsg(queueName, type, originator, null, metaData, data); + public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data) { + return newMsg(queueId, type, originator, null, metaData, data); } - public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + public static TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { + return new TbMsg(queueId, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); } @@ -109,50 +108,50 @@ public final class TbMsg implements Serializable { // For Tests only public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); } public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, + return new TbMsg(tbMsg.queueId, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); } public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(tbMsg.queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(tbMsg.queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); } - public static TbMsg transformMsg(TbMsg tbMsg, String queueName) { - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + public static TbMsg transformMsg(TbMsg tbMsg, QueueId queueId) { + return new TbMsg(queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback()); } - public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, String queueName) { - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, QueueId queueId) { + return new TbMsg(queueId, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); } //used for enqueueForTellNext - public static TbMsg newMsg(TbMsg tbMsg, String queueName, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(), + public static TbMsg newMsg(TbMsg tbMsg, QueueId queueId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + return new TbMsg(queueId, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(), tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ctx.copy(), TbMsgCallback.EMPTY); } - private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, + private TbMsg(QueueId queueId, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { this.id = id; - this.queueName = queueName != null ? queueName : ServiceQueue.MAIN; + this.queueId = queueId; if (ts > 0) { this.ts = ts; } else { @@ -221,7 +220,7 @@ public final class TbMsg implements Serializable { return builder.build().toByteArray(); } - public static TbMsg fromBytes(String queueName, byte[] data, TbMsgCallback callback) { + public static TbMsg fromBytes(QueueId queueId, byte[] data, TbMsgCallback callback) { try { MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data); TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); @@ -248,7 +247,7 @@ public final class TbMsg implements Serializable { } TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; - return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, + return new TbMsg(queueId, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, ctx, callback); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Could not parse protobuf for TbMsg", e); @@ -260,12 +259,12 @@ public final class TbMsg implements Serializable { } public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + return new TbMsg(this.queueId, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, null, this.ctx, callback); } public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + return new TbMsg(this.queueId, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback); } @@ -278,10 +277,6 @@ public final class TbMsg implements Serializable { } } - public String getQueueName() { - return queueName != null ? queueName : ServiceQueue.MAIN; - } - public void pushToStack(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { ctx.push(ruleChainId, ruleNodeId); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 58ef13ac6d..ce7c93741a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceQueueKey; @@ -62,6 +63,7 @@ public class HashPartitionService implements PartitionService { private final TbServiceInfoProvider serviceInfoProvider; private final TenantRoutingInfoService tenantRoutingInfoService; private final QueueRoutingInfoService queueRoutingInfoService; + private final ConcurrentMap queueNames = new ConcurrentHashMap<>(); private final ConcurrentMap> partitionTopicsMap = new ConcurrentHashMap<>(); private final ConcurrentMap> partitionSizesMap = new ConcurrentHashMap<>(); private final ConcurrentMap tenantRoutingInfoMap = new ConcurrentHashMap<>(); @@ -91,27 +93,21 @@ public class HashPartitionService implements PartitionService { } private void partitionsInit() { - addPartitionSizeToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE, "Main"), corePartitions); - addPartitionTopicToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE, "Main"), coreTopic); + addPartitionSizeToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE), corePartitions); + addPartitionTopicToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE), coreTopic); List queueRoutingInfoList; String serviceType = serviceInfoProvider.getServiceType(); - if ("tb-rule-engine".equals(serviceType)) { - queueRoutingInfoList = queueRoutingInfoService.getQueuesRoutingInfo(serviceInfoProvider.getIsolatedTenant().orElse(TenantId.SYS_TENANT_ID)); - } else if ("monolith".equals(serviceType)) { - queueRoutingInfoList = queueRoutingInfoService.getAllQueuesRoutingInfo(); - } else if ("tb-core".equals(serviceType)) { - queueRoutingInfoList = queueRoutingInfoService.getMainQueuesRoutingInfo(); - } else { + if ("tb-transport".equals(serviceType)) { //If transport started earlier than tb-core int getQueuesRetries = 10; while (true) { if (getQueuesRetries > 0) { log.info("Try to get queue routing info."); try { - queueRoutingInfoList = queueRoutingInfoService.getMainQueuesRoutingInfo(); + queueRoutingInfoList = queueRoutingInfoService.getAllQueuesRoutingInfo(); break; } catch (Exception e) { log.info("Failed to get queues routing info!"); @@ -126,11 +122,14 @@ public class HashPartitionService implements PartitionService { throw new RuntimeException("Failed to await queues routing info!"); } } + } else { + queueRoutingInfoList = queueRoutingInfoService.getAllQueuesRoutingInfo(); } queueRoutingInfoList.forEach(queue -> { addPartitionTopicToMap(queue.getTenantId(), new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getQueueName()), queue.getQueueTopic()); addPartitionSizeToMap(queue.getTenantId(), new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getQueueName()), queue.getPartitions()); + queueNames.put(queue.getQueueId(), queue.getQueueName()); }); } @@ -139,6 +138,8 @@ public class HashPartitionService implements PartitionService { TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); addPartitionTopicToMap(tenantId, new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName()), queueUpdateMsg.getQueueTopic()); addPartitionSizeToMap(tenantId, new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName()), queueUpdateMsg.getPartitions()); + queueNames.putIfAbsent(new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())), queueUpdateMsg.getQueueName()); + tpiCache.clear(); } @Override @@ -148,6 +149,8 @@ public class HashPartitionService implements PartitionService { partitionTopicsMap.get(tenantId).remove(serviceQueue); partitionSizesMap.get(tenantId).remove(serviceQueue); myPartitions.remove(new ServiceQueueKey(serviceQueue, tenantId)); + queueNames.remove(new QueueId(new UUID(queueDeleteMsg.getQueueIdMSB(), queueDeleteMsg.getQueueIdLSB()))); + tpiCache.clear(); } private void addPartitionSizeToMap(TenantId tenantId, ServiceQueue serviceQueue, int partitions) { @@ -164,13 +167,14 @@ public class HashPartitionService implements PartitionService { } @Override - public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) { - ServiceQueue serviceQueue = new ServiceQueue(serviceType, queueName); - ConcurrentMap queues = partitionTopicsMap.get(getSystemIsolatedTenantId(serviceType, tenantId)); - - if (!queues.containsKey(serviceQueue)) { - serviceQueue = new ServiceQueue(serviceType); + public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) { + String queueName; + if (queueId == null) { + queueName = ServiceQueue.MAIN; + } else { + queueName = queueNames.get(queueId); } + ServiceQueue serviceQueue = new ServiceQueue(serviceType, queueName); return resolve(serviceQueue, tenantId, entityId); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java index 84065ec283..6fbd3d32e2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.queue.discovery; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -33,7 +34,7 @@ public interface PartitionService { TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId); - TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId); + TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId); /** * Received from the Discovery service when network topology is changed. diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java index 8afecc4413..111ca5626a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java @@ -16,6 +16,7 @@ package org.thingsboard.server.queue.discovery; import lombok.Data; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.gen.transport.TransportProtos.GetQueueRoutingInfoResponseMsg; @@ -27,19 +28,14 @@ import java.util.UUID; public class QueueRoutingInfo { private final TenantId tenantId; + private final QueueId queueId; private final String queueName; private final String queueTopic; private final int partitions; - public QueueRoutingInfo(TenantId tenantId, String queueName, String queueTopic, int partitions) { - this.tenantId = tenantId; - this.queueName = queueName; - this.queueTopic = queueTopic; - this.partitions = partitions; - } - public QueueRoutingInfo(Queue queue) { this.tenantId = queue.getTenantId(); + this.queueId = queue.getId(); this.queueName = queue.getName(); this.queueTopic = queue.getTopic(); this.partitions = queue.getPartitions(); @@ -47,6 +43,7 @@ public class QueueRoutingInfo { public QueueRoutingInfo(GetQueueRoutingInfoResponseMsg routingInfo) { this.tenantId = new TenantId(new UUID(routingInfo.getTenantIdMSB(), routingInfo.getTenantIdLSB())); + this.queueId = new QueueId(new UUID(routingInfo.getQueueIdMSB(), routingInfo.getQueueIdLSB())); this.queueName = routingInfo.getQueueName(); this.queueTopic = routingInfo.getQueueTopic(); this.partitions = routingInfo.getPartitions(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java index 366452d9e8..98cd5cccba 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfoService.java @@ -15,15 +15,10 @@ */ package org.thingsboard.server.queue.discovery; -import org.thingsboard.server.common.data.id.TenantId; - import java.util.List; public interface QueueRoutingInfoService { List getAllQueuesRoutingInfo(); - List getMainQueuesRoutingInfo(); - - List getQueuesRoutingInfo(TenantId tenantId); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java index 53c1997f5c..f1d3f7e26c 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java @@ -68,10 +68,6 @@ public interface TransportService { GetEntityProfileResponseMsg getEntityProfile(GetEntityProfileRequestMsg msg); - List getQueueRoutingInfo(TransportProtos.GetAllMainQueueRoutingInfoRequestMsg msg); - - List getQueueRoutingInfo(TransportProtos.GetTenantQueueRoutingInfoRequestMsg msg); - List getQueueRoutingInfo(TransportProtos.GetAllQueueRoutingInfoRequestMsg msg); GetResourceResponseMsg getResource(GetResourceRequestMsg msg); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index f06a7f76ea..70a9ae1225 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -44,13 +44,13 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.session.SessionMsgType; @@ -322,30 +322,6 @@ public class DefaultTransportService implements TransportService { } } - @Override - public List getQueueRoutingInfo(TransportProtos.GetAllMainQueueRoutingInfoRequestMsg msg) { - TbProtoQueueMsg protoMsg = - new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetAllMainQueueRoutingInfoRequestMsg(msg).build()); - try { - TbProtoQueueMsg response = transportApiRequestTemplate.send(protoMsg).get(); - return response.getValue().getGetQueueRoutingInfoResponseMsgsList(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - } - - @Override - public List getQueueRoutingInfo(TransportProtos.GetTenantQueueRoutingInfoRequestMsg msg) { - TbProtoQueueMsg protoMsg = - new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetTenantQueueRoutingInfoRequestMsg(msg).build()); - try { - TbProtoQueueMsg response = transportApiRequestTemplate.send(protoMsg).get(); - return response.getValue().getGetQueueRoutingInfoResponseMsgsList(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - } - @Override public TransportProtos.GetResourceResponseMsg getResource(TransportProtos.GetResourceRequestMsg msg) { TbProtoQueueMsg protoMsg = @@ -1112,7 +1088,7 @@ public class DefaultTransportService implements TransportService { } private void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) { - TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, tbMsg.getOriginator()); + TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueId(), tenantId, tbMsg.getOriginator()); if (log.isTraceEnabled()) { log.trace("[{}][{}] Pushing to topic {} message {}", tenantId, tbMsg.getOriginator(), tpi.getFullTopicName(), tbMsg); } @@ -1129,19 +1105,18 @@ public class DefaultTransportService implements TransportService { DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); RuleChainId ruleChainId; - String queueName; + QueueId queueId; if (deviceProfile == null) { log.warn("[{}] Device profile is null!", deviceProfileId); ruleChainId = null; - queueName = ServiceQueue.MAIN; + queueId = null; } else { ruleChainId = deviceProfile.getDefaultRuleChainId(); - String defaultQueueName = deviceProfile.getDefaultQueueName(); - queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN; + queueId = deviceProfile.getDefaultQueueId(); } - TbMsg tbMsg = TbMsg.newMsg(queueName, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null); + TbMsg tbMsg = TbMsg.newMsg(queueId, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null); sendToRuleEngine(tenantId, tbMsg, callback); } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java index 537a86b1d6..ae1b6934c3 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportQueueRoutingInfoService.java @@ -20,11 +20,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos.GetAllQueueRoutingInfoRequestMsg; -import org.thingsboard.server.gen.transport.TransportProtos.GetAllMainQueueRoutingInfoRequestMsg; -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantQueueRoutingInfoRequestMsg; import org.thingsboard.server.queue.discovery.QueueRoutingInfo; import org.thingsboard.server.queue.discovery.QueueRoutingInfoService; @@ -45,16 +42,4 @@ public class TransportQueueRoutingInfoService implements QueueRoutingInfoService GetAllQueueRoutingInfoRequestMsg msg = GetAllQueueRoutingInfoRequestMsg.newBuilder().build(); return transportService.getQueueRoutingInfo(msg).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); } - - @Override - public List getMainQueuesRoutingInfo() { - GetAllMainQueueRoutingInfoRequestMsg msg = GetAllMainQueueRoutingInfoRequestMsg.newBuilder().build(); - return transportService.getQueueRoutingInfo(msg).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); - } - - @Override - public List getQueuesRoutingInfo(TenantId tenantId) { - GetTenantQueueRoutingInfoRequestMsg msg = GetTenantQueueRoutingInfoRequestMsg.newBuilder().build(); - return transportService.getQueueRoutingInfo(msg).stream().map(QueueRoutingInfo::new).collect(Collectors.toList()); - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 7d6412cbea..7bfacb5f78 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -114,7 +114,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D return "[Transport Configuration] invalid " + schemaName + " provided!"; } - @Autowired(required = false) + @Autowired private QueueService queueService; @Autowired @@ -386,13 +386,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D throw new DataValidationException("Another default device profile is present in scope of current tenant!"); } } - if (!StringUtils.isEmpty(deviceProfile.getDefaultQueueName()) && queueService != null) { - //TODO: Yevhen replace queue name to queue id - if (!queueService.findQueuesByTenantId(tenantId) - .stream() - .map(Queue::getName) - .collect(Collectors.toSet()) - .contains(deviceProfile.getDefaultQueueName())) { + if (deviceProfile.getDefaultQueueId() != null) { + Queue queue = queueService.findQueueById(tenantId, deviceProfile.getDefaultQueueId()); + if (queue == null) { throw new DataValidationException("Device profile is referencing to non-existent queue!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 73c19cab3c..c9f89ccc91 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -180,7 +180,7 @@ public class ModelConstants { public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default"; 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_QUEUE_NAME_PROPERTY = "default_queue_name"; + public static final String DEVICE_PROFILE_DEFAULT_QUEUE_ID_PROPERTY = "default_queue_id"; 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_SOFTWARE_ID_PROPERTY = "software_id"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java index bd214a6cbc..9dc5c9780e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -87,8 +88,8 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY) private UUID defaultDashboardId; - @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY) - private String defaultQueueName; + @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_QUEUE_ID_PROPERTY) + private UUID defaultQueueId; @Type(type = "jsonb") @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") @@ -129,7 +130,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl if (deviceProfile.getDefaultDashboardId() != null) { this.defaultDashboardId = deviceProfile.getDefaultDashboardId().getId(); } - this.defaultQueueName = deviceProfile.getDefaultQueueName(); + if (deviceProfile.getDefaultQueueId() != null) { + this.defaultQueueId = deviceProfile.getDefaultQueueId().getId(); + } this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); if (deviceProfile.getFirmwareId() != null) { this.firmwareId = deviceProfile.getFirmwareId().getId(); @@ -174,7 +177,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl if (defaultDashboardId != null) { deviceProfile.setDefaultDashboardId(new DashboardId(defaultDashboardId)); } - deviceProfile.setDefaultQueueName(defaultQueueName); + if (defaultQueueId != null) { + deviceProfile.setDefaultQueueId(new QueueId(defaultQueueId)); + } deviceProfile.setProvisionDeviceKey(provisionDeviceKey); if (firmwareId != null) { diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 54c3cbfa93..b85171efee 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -216,6 +216,20 @@ CREATE TABLE IF NOT EXISTS ota_package ( -- CONSTRAINT fk_device_profile_firmware FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE ); +CREATE TABLE IF NOT EXISTS queue( + id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY, + created_time bigint NOT NULL, + tenant_id uuid, + name varchar(255), + topic varchar(255), + poll_interval int, + partitions int, + consumer_per_partition boolean, + pack_processing_timeout bigint, + submit_strategy varchar(255), + processing_strategy varchar(255) +); + CREATE TABLE IF NOT EXISTS device_profile ( id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, created_time bigint NOT NULL, @@ -233,12 +247,13 @@ CREATE TABLE IF NOT EXISTS device_profile ( software_id uuid, default_rule_chain_id uuid, default_dashboard_id uuid, - default_queue_name varchar(255), + default_queue_id uuid, provision_device_key varchar, CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 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_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_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id) ); @@ -634,20 +649,6 @@ CREATE TABLE IF NOT EXISTS rpc ( status varchar(255) NOT NULL ); -CREATE TABLE IF NOT EXISTS queue( - id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY, - created_time bigint NOT NULL, - tenant_id uuid, - name varchar(255), - topic varchar(255), - poll_interval int, - partitions int, - consumer_per_partition boolean, - pack_processing_timeout bigint, - submit_strategy varchar(255), - processing_strategy varchar(255) -); - CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint) LANGUAGE plpgsql AS $$ diff --git a/dao/src/test/resources/sql/system-data.sql b/dao/src/test/resources/sql/system-data.sql index 339d6e94ba..1d0d29aec5 100644 --- a/dao/src/test/resources/sql/system-data.sql +++ b/dao/src/test/resources/sql/system-data.sql @@ -43,3 +43,9 @@ VALUES ( '6eaaefa6-4612-11e7-a919-92ebcb67fe33', 1592576748000, 'mail', '{ "username": "", "password": "" }' ); + +INSERT INTO queue ( id, created_time, tenant_id, name, topic, poll_interval, partitions, consumer_per_partition, pack_processing_timeout, submit_strategy, processing_strategy ) +VALUES ( '6eaaefa6-4612-11e7-a919-92ebcb67fe33', 1592576748000 ,'13814000-1dd2-11b2-8080-808080808080', 'Main' ,'tb_rule_engine.main', 25, 10, true, 2000, + '{"type": "BURST", "batchSize": 1000}', + '{"type": "SKIP_ALL_FAILURES", "retries": 3, "failurePercentage": 0.0, "pauseBetweenRetries": 3, "maxPauseBetweenRetries": 3}' +); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index ee2a93d7fb..ce66b4fbce 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; @@ -50,6 +51,7 @@ import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.nosql.CassandraStatementTask; import org.thingsboard.server.dao.nosql.TbResultSetFuture; import org.thingsboard.server.dao.ota.OtaPackageService; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -145,7 +147,7 @@ public interface TbContext { * * @param msg - message */ - void enqueue(TbMsg msg, String queueName, Runnable onSuccess, Consumer onFailure); + void enqueue(TbMsg msg, QueueId queueId, Runnable onSuccess, Consumer onFailure); void enqueueForTellFailure(TbMsg msg, String failureMessage); @@ -157,15 +159,15 @@ public interface TbContext { void enqueueForTellNext(TbMsg msg, Set relationTypes, Runnable onSuccess, Consumer onFailure); - void enqueueForTellNext(TbMsg msg, String queueName, String relationType, Runnable onSuccess, Consumer onFailure); + void enqueueForTellNext(TbMsg msg, QueueId queueId, String relationType, Runnable onSuccess, Consumer onFailure); - void enqueueForTellNext(TbMsg msg, String queueName, Set relationTypes, Runnable onSuccess, Consumer onFailure); + void enqueueForTellNext(TbMsg msg, QueueId queueId, Set relationTypes, Runnable onSuccess, Consumer onFailure); void ack(TbMsg tbMsg); - TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data); + TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data); - TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data); + TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data); TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data); @@ -236,6 +238,8 @@ public interface TbContext { EdgeEventService getEdgeEventService(); + QueueService getQueueService(); + ListeningExecutor getMailExecutor(); ListeningExecutor getSmsExecutor(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index fe2d5a4cd4..b27caf6838 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -136,7 +136,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { } private void transformAndTellNext(TbContext ctx, TbMsg msg, EntityView entityView) { - ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueName(), msg.getType(), entityView.getId(), msg.getCustomerId(), msg.getMetaData(), msg.getData()), SUCCESS); + ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueId(), msg.getType(), entityView.getId(), msg.getCustomerId(), msg.getMetaData(), msg.getData()), SUCCESS); } private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index 97f9f8565c..4a29787762 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -78,7 +78,7 @@ public class TbMsgCountNode implements TbNode { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay)); - TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson)); + TbMsg tbMsg = TbMsg.newMsg(msg.getQueueId(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson)); ctx.enqueueForTellNext(tbMsg, SUCCESS); scheduleTickMsg(ctx, tbMsg); } else { @@ -94,7 +94,7 @@ public class TbMsgCountNode implements TbNode { } lastScheduledTs = lastScheduledTs + delay; long curDelay = Math.max(0L, (lastScheduledTs - curTs)); - TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_COUNT_NODE_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, new TbMsgMetaData(), ""); + TbMsg tickMsg = ctx.newMsg(null, TB_MSG_COUNT_NODE_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, new TbMsgMetaData(), ""); nextTickId = tickMsg.getId(); ctx.tellSelf(tickMsg, curDelay); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index 5ffa9ba5b5..f8b4d64b42 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -135,7 +135,7 @@ public class TbMsgGeneratorNode implements TbNode { } lastScheduledTs = lastScheduledTs + delay; long curDelay = Math.max(0L, (lastScheduledTs - curTs)); - TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); + TbMsg tickMsg = ctx.newMsg(null, TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); nextTickId = tickMsg.getId(); ctx.tellSelf(tickMsg, curDelay); } @@ -143,14 +143,14 @@ public class TbMsgGeneratorNode implements TbNode { private ListenableFuture generate(TbContext ctx, TbMsg msg) { log.trace("generate, config {}", config); if (prevMsg == null) { - prevMsg = ctx.newMsg(ServiceQueue.MAIN, "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}"); + prevMsg = ctx.newMsg(null, "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}"); } if (initialized.get()) { ctx.logJsEvalRequest(); return Futures.transformAsync(jsEngine.executeGenerateAsync(prevMsg), generated -> { log.trace("generate process response, generated {}, config {}", generated, config); ctx.logJsEvalResponse(); - prevMsg = ctx.newMsg(ServiceQueue.MAIN, generated.getType(), originatorId, msg.getCustomerId(), generated.getMetaData(), generated.getData()); + prevMsg = ctx.newMsg(null, generated.getType(), originatorId, msg.getCustomerId(), generated.getMetaData(), generated.getData()); return Futures.immediateFuture(prevMsg); }, MoreExecutors.directExecutor()); //usually it runs on js-executor-remote-callback thread pool } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index 57d087e42a..464acadb94 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -73,7 +73,7 @@ public class TbMsgDelayNode implements TbNode { } else { if (pendingMsgs.size() < config.getMaxPendingMsgs()) { pendingMsgs.put(msg.getId(), msg); - TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_DELAY_NODE_MSG, ctx.getSelfId(), msg.getCustomerId(), new TbMsgMetaData(), msg.getId().toString()); + TbMsg tickMsg = ctx.newMsg(null, TB_MSG_DELAY_NODE_MSG, ctx.getSelfId(), msg.getCustomerId(), new TbMsgMetaData(), msg.getId().toString()); ctx.tellSelf(tickMsg, getDelay(msg)); ctx.ack(msg); } else { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java index 286ffea9d2..9bd51dfdf4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java @@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.flow; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; -import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; @@ -25,10 +24,9 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.TbMsg; -import static org.thingsboard.common.util.DonAsynchron.withCallback; - @Slf4j @RuleNode( type = ComponentType.FLOW, @@ -46,11 +44,17 @@ public class TbCheckpointNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class); + if (config.getQueueId() == null) { + Queue foundQueue = ctx.getQueueService().findQueueByTenantIdAndName(ctx.getTenantId(), config.getQueueName()); + if (foundQueue != null) { + config.setQueueId(foundQueue.getId()); + } + } } @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.enqueueForTellNext(msg, config.getQueueName(), TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); + ctx.enqueueForTellNext(msg, config.getQueueId(), TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java index 9957e6b07c..b2da9142d7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java @@ -17,12 +17,15 @@ package org.thingsboard.rule.engine.flow; import lombok.Data; import org.thingsboard.rule.engine.api.NodeConfiguration; +import org.thingsboard.server.common.data.id.QueueId; @Data public class TbCheckpointNodeConfiguration implements NodeConfiguration { private String queueName; + private QueueId queueId; + @Override public TbCheckpointNodeConfiguration defaultConfiguration() { TbCheckpointNodeConfiguration configuration = new TbCheckpointNodeConfiguration(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 2a46b77791..db41c0f6d5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -36,9 +36,9 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionSpecType; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.dao.alarm.AlarmOperationResult; import java.util.ArrayList; @@ -60,7 +60,7 @@ class AlarmState { private volatile Alarm currentAlarm; private volatile boolean initialFetchDone; private volatile TbMsgMetaData lastMsgMetaData; - private volatile String lastMsgQueueName; + private volatile QueueId lastMsgQueueId; private volatile DataSnapshot dataSnapshot; private final DynamicPredicateValueCtx dynamicPredicateValueCtx; @@ -74,7 +74,7 @@ class AlarmState { public boolean process(TbContext ctx, TbMsg msg, DataSnapshot data, SnapshotUpdate update) throws ExecutionException, InterruptedException { initCurrentAlarm(ctx); lastMsgMetaData = msg.getMetaData(); - lastMsgQueueName = msg.getQueueName(); + lastMsgQueueId = msg.getQueueId(); this.dataSnapshot = data; try { return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval); @@ -195,7 +195,7 @@ class AlarmState { metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString()); } setAlarmConditionMetadata(ruleState, metaData); - TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : ServiceQueue.MAIN, "ALARM", + TbMsg newMsg = ctx.newMsg(lastMsgQueueId != null ? lastMsgQueueId : null, "ALARM", originator, msg != null ? msg.getCustomerId() : null, metaData, data); ctx.enqueueForTellNext(newMsg, relationType); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java index 45b45e91f9..265475c0d9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java +++ b/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 -> { if (ruleEngineDeviceRpcResponse.getError().isEmpty()) { - TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}")); + TbMsg next = ctx.newMsg(msg.getQueueId(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}")); ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS); } else { - TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name())); + TbMsg next = ctx.newMsg(msg.getQueueId(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name())); ctx.enqueueForTellFailure(next, ruleEngineDeviceRpcResponse.getError().get().name()); } }); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index dcad6f1567..b00713cefa 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -188,7 +188,7 @@ public class TbDeviceProfileNodeTest { Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg()); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg); + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); data.put("temperature", 42); @@ -200,7 +200,7 @@ public class TbDeviceProfileNodeTest { verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); TbMsg theMsg2 = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "2"); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg2); + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg2); TbMsg msg2 = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), @@ -279,7 +279,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(attrListListenableFuture); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -366,7 +366,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(attrListListenableFuture); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -435,7 +435,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -529,7 +529,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -653,7 +653,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listNoDurationAttribute); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -762,7 +762,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -878,7 +878,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listNoDurationAttribute); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -974,7 +974,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -1072,7 +1072,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -1153,7 +1153,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -1227,7 +1227,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -1311,7 +1311,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); @@ -1397,7 +1397,7 @@ public class TbDeviceProfileNodeTest { .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = mapper.createObjectNode(); diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index b71f5a95ef..71e2a3de95 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -83,15 +83,12 @@ import { import { alarmFields } from '@shared/models/alarm.models'; import { OtaPackageService } from '@core/http/ota-package.service'; import { EdgeService } from '@core/http/edge.service'; -import { - Edge, - EdgeEvent, - EdgeEventType, - bodyContentEdgeEventActionTypes -} from '@shared/models/edge.models'; +import { bodyContentEdgeEventActionTypes, Edge, EdgeEvent, EdgeEventType } from '@shared/models/edge.models'; import { RuleChainMetaData, RuleChainType } from '@shared/models/rule-chain.models'; import { WidgetService } from '@core/http/widget.service'; import { DeviceProfileService } from '@core/http/device-profile.service'; +import { QueueService } from "@core/http/queue.service"; +import { ServiceType } from "@shared/models/queue.models"; @Injectable({ providedIn: 'root' @@ -115,7 +112,8 @@ export class EntityService { private otaPackageService: OtaPackageService, private widgetService: WidgetService, private deviceProfileService: DeviceProfileService, - private utils: UtilsService + private utils: UtilsService, + private queueService: QueueService ) { } private getEntityObservable(entityType: EntityType, entityId: string, @@ -156,6 +154,9 @@ export class EntityService { case EntityType.OTA_PACKAGE: observable = this.otaPackageService.getOtaPackageInfo(entityId, config); break; + case EntityType.QUEUE: + observable = this.queueService.getQueueById(entityId, config); + break; } return observable; } diff --git a/ui-ngx/src/app/core/http/queue.service.ts b/ui-ngx/src/app/core/http/queue.service.ts index dc98c15d39..bf2183449d 100644 --- a/ui-ngx/src/app/core/http/queue.service.ts +++ b/ui-ngx/src/app/core/http/queue.service.ts @@ -36,8 +36,8 @@ export class QueueService { defaultHttpOptionsFromConfig(config)); } - public getQueueById(queueId: string): Observable { - return this.http.get(`/api/tenant/queues/${queueId}`); + public getQueueById(queueId: string, config?: RequestConfig): Observable { + return this.http.get(`/api/tenant/queues/${queueId}`, defaultHttpOptionsFromConfig(config)); } public getTenantQueuesByServiceType(pageLink: PageLink, diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index 96584a7ba8..ace76e27cd 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -54,10 +54,10 @@ formControlName="defaultDashboardId">
{{'device-profile.mobile-dashboard-hint' | translate}}
- - + formControlName="defaultQueueId"> + device-profile.type diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index b5535b22cd..2d80e9a25b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -50,6 +50,7 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { deepTrim } from '@core/utils'; import { ServiceType } from '@shared/models/queue.models'; import { DashboardId } from '@shared/models/id/dashboard-id'; +import { QueueId } from "@shared/models/id/queue-id"; export interface AddDeviceProfileDialogData { deviceProfileName: string; @@ -110,7 +111,7 @@ export class AddDeviceProfileDialogComponent extends image: [null, []], defaultRuleChainId: [null, []], defaultDashboardId: [null, []], - defaultQueueName: ['', []], + defaultQueueId: [null, []], description: ['', []] } ); @@ -187,7 +188,7 @@ export class AddDeviceProfileDialogComponent extends name: this.deviceProfileDetailsFormGroup.get('name').value, type: this.deviceProfileDetailsFormGroup.get('type').value, image: this.deviceProfileDetailsFormGroup.get('image').value, - defaultQueueName: this.deviceProfileDetailsFormGroup.get('defaultQueueName').value, + // defaultQueueId: this.deviceProfileDetailsFormGroup.get('defaultQueueId').value, transportType: this.transportConfigFormGroup.get('transportType').value, provisionType: deviceProvisionConfiguration.type, provisionDeviceKey, @@ -205,6 +206,9 @@ export class AddDeviceProfileDialogComponent extends if (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( (savedDeviceProfile) => { this.dialogRef.close(savedDeviceProfile); diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 565eb5b160..f5b9c15a0f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -73,10 +73,10 @@ formControlName="defaultDashboardId">
{{'device-profile.mobile-dashboard-hint' | translate}}
- - + formControlName="defaultQueueId"> + { }), defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], defaultDashboardId: [entity && entity.defaultDashboardId ? entity.defaultDashboardId.id : null, []], - defaultQueueName: [entity ? entity.defaultQueueName : '', []], + defaultQueueId: [entity && entity.defaultQueueId ? entity.defaultQueueId.id : null, []], firmwareId: [entity ? entity.firmwareId : null], softwareId: [entity ? entity.softwareId : null], description: [entity ? entity.description : '', []], @@ -197,7 +198,7 @@ export class DeviceProfileComponent extends EntityComponent { }}, {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({defaultQueueName: entity.defaultQueueName}, {emitEvent: false}); + this.entityForm.patchValue({defaultQueueId: entity.defaultQueueId ? entity.defaultQueueId.id: null}, {emitEvent: false}); this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false}); this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); @@ -210,6 +211,9 @@ export class DeviceProfileComponent extends EntityComponent { if (formValue.defaultDashboardId) { formValue.defaultDashboardId = new DashboardId(formValue.defaultDashboardId); } + if (formValue.defaultQueueId) { + formValue.defaultQueueId = new QueueId(formValue.defaultQueueId); + } const deviceProvisionConfiguration: DeviceProvisionConfiguration = formValue.profileData.provisionConfiguration; formValue.provisionType = deviceProvisionConfiguration.type; formValue.provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey; diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 6b00667509..9cd7460c85 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -92,11 +92,11 @@
- - + formControlName="defaultQueueId"> +
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss index 31594ada95..ffeaad5acd 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss @@ -64,7 +64,7 @@ } } - tb-device-profile-autocomplete, tb-queue-type-list{ + tb-device-profile-autocomplete, tb-queue-autocomplete{ .mat-form-field-wrapper{ width: 180px !important; } diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 694deabd96..1f1a5266ba 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -49,6 +49,7 @@ import { MediaBreakpoints } from '@shared/models/constants'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { ServiceType } from '@shared/models/queue.models'; import { deepTrim } from '@core/utils'; +import { QueueId } from "@shared/models/id/queue-id"; @Component({ selector: 'tb-device-wizard', @@ -113,7 +114,7 @@ export class DeviceWizardDialogComponent extends deviceProfileId: [null, Validators.required], newDeviceProfileTitle: [{value: null, disabled: true}], defaultRuleChainId: [{value: null, disabled: true}], - defaultQueueName: [{value: null, disabled: true}], + defaultQueueId: [{value: null, disabled: true}], description: [''] } ); @@ -126,7 +127,7 @@ export class DeviceWizardDialogComponent extends this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null); this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable(); this.deviceWizardFormGroup.get('defaultRuleChainId').disable(); - this.deviceWizardFormGroup.get('defaultQueueName').disable(); + this.deviceWizardFormGroup.get('defaultQueueId').disable(); this.deviceWizardFormGroup.updateValueAndValidity(); this.createProfile = false; } else { @@ -135,7 +136,7 @@ export class DeviceWizardDialogComponent extends this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]); this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable(); this.deviceWizardFormGroup.get('defaultRuleChainId').enable(); - this.deviceWizardFormGroup.get('defaultQueueName').enable(); + this.deviceWizardFormGroup.get('defaultQueueId').enable(); this.deviceWizardFormGroup.updateValueAndValidity(); this.createProfile = true; @@ -297,7 +298,6 @@ export class DeviceWizardDialogComponent extends const deviceProfile: DeviceProfile = { name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value, type: DeviceProfileType.DEFAULT, - defaultQueueName: this.deviceWizardFormGroup.get('defaultQueueName').value, transportType: this.transportConfigFormGroup.get('transportType').value, provisionType: deviceProvisionConfiguration.type, provisionDeviceKey, @@ -311,6 +311,9 @@ export class DeviceWizardDialogComponent extends if (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( tap((profile) => { this.currentDeviceProfileTransportType = profile.transportType; diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html new file mode 100644 index 0000000000..db9e899f1b --- /dev/null +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html @@ -0,0 +1,54 @@ + + + + + + + + + +
+
+ device-profile.no-device-profiles-found +
+ + + {{ translate.get('queue.no-queues-matching', + {entity: truncate.transform(searchText, true, 6, '...')}) | async }} + + +
+
+
+ + {{ 'queue.queue-required' | translate }} + +
diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts new file mode 100644 index 0000000000..28f40425ea --- /dev/null +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts @@ -0,0 +1,215 @@ +/// +/// 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. +/// + +import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Observable, of } from 'rxjs'; +import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { TranslateService } from '@ngx-translate/core'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { EntityId } from '@shared/models/id/entity-id'; +import { EntityType } from '@shared/models/entity-type.models'; +import { BaseData } from '@shared/models/base-data'; +import { EntityService } from '@core/http/entity.service'; +import { TruncatePipe } from '@shared/pipe/truncate.pipe'; +import {QueueInfo, ServiceType} from "@shared/models/queue.models"; +import { QueueService } from "@core/http/queue.service"; +import { PageLink } from "@shared/models/page/page-link"; +import { Direction } from "@shared/models/page/sort-order"; +import { emptyPageData } from "@shared/models/page/page-data"; + +@Component({ + selector: 'tb-queue-autocomplete', + templateUrl: './queue-autocomplete.component.html', + styleUrls: [], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => QueueAutocompleteComponent), + multi: true + }] +}) +export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit { + + selectQueueFormGroup: FormGroup; + + modelValue: string | null; + + @Input() + labelText: string; + + @Input() + requiredText: string; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + @Input() + queueType: ServiceType; + + @Input() + disabled: boolean; + + @ViewChild('queueInput', {static: true}) queueInput: ElementRef; + + filteredQueues: Observable>>; + + searchText = ''; + + private dirty = false; + + private propagateChange = (v: any) => { }; + + constructor(private store: Store, + public translate: TranslateService, + public truncate: TruncatePipe, + private entityService: EntityService, + private queueService: QueueService, + private fb: FormBuilder) { + this.selectQueueFormGroup = this.fb.group({ + queueId: [null] + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.filteredQueues = this.selectQueueFormGroup.get('queueId').valueChanges + .pipe( + debounceTime(150), + tap(value => { + let modelValue; + if (typeof value === 'string' || !value) { + modelValue = null; + } else { + modelValue = value.id.id; + } + this.updateView(modelValue); + if (value === null) { + this.clear(); + } + }), + map(value => value ? (typeof value === 'string' ? value : value.name) : ''), + distinctUntilChanged(), + switchMap(name => this.fetchQueue(name) ), + share() + ); + } + + ngAfterViewInit(): void {} + + getCurrentEntity(): BaseData | null { + const currentRuleChain = this.selectQueueFormGroup.get('queueId').value; + if (currentRuleChain && typeof currentRuleChain !== 'string') { + return currentRuleChain as BaseData; + } else { + return null; + } + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.selectQueueFormGroup.disable({emitEvent: false}); + } else { + this.selectQueueFormGroup.enable({emitEvent: false}); + } + } + + textIsNotEmpty(text: string): boolean { + return (text && text.length > 0); + } + + writeValue(value: string | null): void { + this.searchText = ''; + if (value != null) { + const targetEntityType = EntityType.QUEUE; + this.entityService.getEntity(targetEntityType, value, {ignoreLoading: true, ignoreErrors: true}).subscribe( + (entity) => { + this.modelValue = entity.id.id; + this.selectQueueFormGroup.get('queueId').patchValue(entity, {emitEvent: false}); + }, + () => { + this.modelValue = null; + this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: false}); + if (value !== null) { + this.propagateChange(this.modelValue); + } + } + ); + } else { + this.modelValue = null; + this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: false}); + } + this.dirty = true; + } + + onFocus() { + if (this.dirty) { + this.selectQueueFormGroup.get('queueId').updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + reset() { + this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: false}); + } + + updateView(value: string | null) { + if (this.modelValue !== value) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } + } + + displayQueueFn(queue?: BaseData): string | undefined { + return queue ? queue.name : undefined; + } + + fetchQueue(searchText?: string): Observable> { + this.searchText = searchText; + const pageLink = new PageLink(10, 0, searchText, { + property: 'name', + direction: Direction.ASC + }); + return this.queueService.getTenantQueuesByServiceType(pageLink, this.queueType, {ignoreLoading: true}).pipe( + catchError(() => of(emptyPageData())), + map(pageData => { + return pageData.data; + }) + ); + } + + clear() { + this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: true}); + setTimeout(() => { + this.queueInput.nativeElement.blur(); + this.queueInput.nativeElement.focus(); + }, 0); + } +} diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index fc47d4c443..c90af9df6a 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -29,6 +29,7 @@ import * as _moment from 'moment'; import { AbstractControl, ValidationErrors } from '@angular/forms'; import { OtaPackageId } from '@shared/models/id/ota-package-id'; import { DashboardId } from '@shared/models/id/dashboard-id'; +import { QueueId } from "@shared/models/id/queue-id"; import { DataType } from '@shared/models/constants'; import { getDefaultProfileClientLwM2mSettingsConfig, @@ -569,7 +570,7 @@ export interface DeviceProfile extends BaseData { provisionDeviceKey?: string; defaultRuleChainId?: RuleChainId; defaultDashboardId?: DashboardId; - defaultQueueName?: string; + defaultQueueId?: QueueId; firmwareId?: OtaPackageId; softwareId?: OtaPackageId; profileData: DeviceProfileData; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index a356fa5921..7a2b0fb28b 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -137,6 +137,7 @@ import { HistorySelectorComponent } from '@shared/components/time/history-select import { EntityGatewaySelectComponent } from '@shared/components/entity/entity-gateway-select.component'; import { DndModule } from 'ngx-drag-drop'; import { QueueTypeListComponent } from '@shared/components/queue/queue-type-list.component'; +import { QueueAutocompleteComponent } from '@shared/components/queue/queue-autocomplete.component'; import { ContactComponent } from '@shared/components/contact.component'; import { TimezoneSelectComponent } from '@shared/components/time/timezone-select.component'; import { FileSizePipe } from '@shared/pipe/file-size.pipe'; @@ -232,6 +233,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) EntityListSelectComponent, EntityTypeListComponent, QueueTypeListComponent, + QueueAutocompleteComponent, RelationTypeAutocompleteComponent, SocialSharePanelComponent, JsonObjectEditComponent, @@ -380,6 +382,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) EntityListSelectComponent, EntityTypeListComponent, QueueTypeListComponent, + QueueAutocompleteComponent, RelationTypeAutocompleteComponent, SocialSharePanelComponent, JsonObjectEditComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 1d09558170..910632d072 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2677,7 +2677,7 @@ "browser-time": "Browser Time" }, "queue": { - "queue-name": "Queue Name", + "queue-name": "Queue", "no-queues-matching": "No queues matching '{{queue}}' were found.", "select-name": "Select queue name", "name": "Name", From 75e2b60eb843be8d14c078207acb3d10d090044b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 19 Apr 2022 23:02:33 +0200 Subject: [PATCH 11/58] Implemented isolated rule engine queue consumers --- .../server/actors/app/AppActor.java | 30 +--- .../actors/service/DefaultActorService.java | 2 +- .../server/actors/tenant/TenantActor.java | 24 +-- .../queue/DefaultTbClusterService.java | 101 +++++------ .../DefaultTbRuleEngineConsumerService.java | 79 +++++---- .../src/main/resources/thingsboard.yml | 1 - .../routing/HashPartitionServiceTest.java | 8 +- .../server/queue/TbQueueClusterService.java | 4 +- common/cluster-api/src/main/proto/queue.proto | 4 +- .../server/dao/queue/QueueService.java | 4 +- .../server/common/data/queue/Queue.java | 13 ++ .../tenant/profile/TenantProfileData.java | 5 + .../TenantProfileQueueConfiguration.java | 32 ++++ .../common/msg/queue/PartitionChangeMsg.java | 2 +- .../common/msg/queue/ServiceQueueKey.java | 14 +- .../DefaultTbServiceInfoProvider.java | 20 --- .../queue/discovery/HashPartitionService.java | 161 +++++++----------- .../server/queue/discovery/QueueKey.java | 56 ++++++ .../queue/discovery/QueueRoutingInfo.java | 9 + .../discovery/TbServiceInfoProvider.java | 5 - .../discovery/TopicPartitionInfoKey.java | 44 ----- .../discovery/event/PartitionChangeEvent.java | 10 +- .../server/dao/queue/BaseQueueService.java | 29 ++-- .../server/dao/tenant/TenantServiceImpl.java | 91 +++++++++- .../rule/engine/action/TbMsgCountNode.java | 1 - .../rule/engine/debug/TbMsgGeneratorNode.java | 1 - .../rule/engine/delay/TbMsgDelayNode.java | 1 - .../import-export/import-export.service.ts | 4 +- .../profile/tenant-profile.component.html | 62 +++---- .../profile/tenant-profile.component.ts | 13 +- ui-ngx/src/app/shared/models/tenant.model.ts | 1 + .../assets/locale/locale.constant-en_US.json | 3 +- 32 files changed, 437 insertions(+), 397 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileQueueConfiguration.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueKey.java delete mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/discovery/TopicPartitionInfoKey.java diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index 7c2e45477b..2817b1e359 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -30,8 +30,6 @@ import org.thingsboard.server.actors.service.DefaultActorService; import org.thingsboard.server.actors.tenant.TenantActor; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; @@ -45,24 +43,20 @@ import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.tenant.TenantService; -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; import java.util.HashSet; -import java.util.Optional; import java.util.Set; @Slf4j public class AppActor extends ContextAwareActor { - private final TbTenantProfileCache tenantProfileCache; private final TenantService tenantService; private final Set deletedTenants; private volatile boolean ruleChainsInitialized; private AppActor(ActorSystemContext systemContext) { super(systemContext); - this.tenantProfileCache = systemContext.getTenantProfileCache(); this.tenantService = systemContext.getTenantService(); this.deletedTenants = new HashSet<>(); } @@ -125,28 +119,12 @@ public class AppActor extends ContextAwareActor { private void initTenantActors() { log.info("Starting main system actor."); try { - // This Service may be started for specific tenant only. - Optional isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant(); - if (isolatedTenantId.isPresent()) { - Tenant tenant = systemContext.getTenantService().findTenantById(isolatedTenantId.get()); - if (tenant != null) { - log.debug("[{}] Creating tenant actor", tenant.getId()); - getOrCreateTenantActor(tenant.getId()); - log.debug("Tenant actor created."); - } else { - log.error("[{}] Tenant with such ID does not exist", isolatedTenantId.get()); - } - } else if (systemContext.isTenantComponentsInitEnabled()) { + if (systemContext.isTenantComponentsInitEnabled()) { PageDataIterable tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); - boolean isRuleEngine = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE); - boolean isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE); for (Tenant tenant : tenantIterator) { - TenantProfile tenantProfile = tenantProfileCache.get(tenant.getTenantProfileId()); - if (isCore || (isRuleEngine && !tenantProfile.isIsolatedTbRuleEngine())) { - log.debug("[{}] Creating tenant actor", tenant.getId()); - getOrCreateTenantActor(tenant.getId()); - log.debug("[{}] Tenant actor created.", tenant.getId()); - } + log.debug("[{}] Creating tenant actor", tenant.getId()); + getOrCreateTenantActor(tenant.getId()); + log.debug("[{}] Tenant actor created.", tenant.getId()); } } log.info("Main system actor started."); diff --git a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java index 2c7faf5226..0809afb4b5 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java @@ -123,7 +123,7 @@ public class DefaultActorService extends TbApplicationEventListener isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant(); - - TenantProfile tenantProfile = systemContext.getTenantProfileCache().get(tenant.getTenantProfileId()); - isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE); isRuleEngineForCurrentTenant = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE); if (isRuleEngineForCurrentTenant) { try { - if (isolatedTenantId.map(id -> id.equals(tenantId)).orElseGet(() -> !tenantProfile.isIsolatedTbRuleEngine())) { - if (apiUsageState.isReExecEnabled()) { - log.info("[{}] Going to init rule chains", tenantId); - initRuleChains(); - } else { - log.info("[{}] Skip init of the rule chains due to API limits", tenantId); - } + if (apiUsageState.isReExecEnabled()) { + log.info("[{}] Going to init rule chains", tenantId); + initRuleChains(); } else { - isRuleEngineForCurrentTenant = false; + log.info("[{}] Skip init of the rule chains due to API limits", tenantId); } } catch (Exception e) { cantFindTenant = true; @@ -138,7 +124,7 @@ public class TenantActor extends RuleChainManagerActor { switch (msg.getMsgType()) { case PARTITION_CHANGE_MSG: PartitionChangeMsg partitionChangeMsg = (PartitionChangeMsg) msg; - ServiceType serviceType = partitionChangeMsg.getServiceQueueKey().getServiceType(); + ServiceType serviceType = partitionChangeMsg.getServiceType(); if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) { //To Rule Chain Actors broadcast(msg); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 102dcbc32c..f1ce95f166 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -26,32 +26,33 @@ import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.EdgeUtils; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; -import org.thingsboard.server.common.data.edge.EdgeEventType; -import org.thingsboard.server.common.data.id.QueueId; -import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto; @@ -70,7 +71,6 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import java.util.HashSet; import java.util.Set; @@ -490,7 +490,7 @@ public class DefaultTbClusterService implements TbClusterService { } @Override - public void onQueueChange(Queue queue, TbQueueCallback callback) { + public void onQueueChange(Queue queue) { log.trace("[{}][{}] Processing queue change [{}] event", queue.getTenantId(), queue.getId(), queue.getName()); TransportProtos.QueueUpdateMsg queueUpdateMsg = TransportProtos.QueueUpdateMsg.newBuilder() @@ -503,38 +503,14 @@ public class DefaultTbClusterService implements TbClusterService { .setPartitions(queue.getPartitions()) .build(); - if ("Main".equals(queue.getName())) { - Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); - for (TransportProtos.ServiceInfo transportService : tbTransportServices) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); - producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); - toTransportNfs.incrementAndGet(); - } - - Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); - ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); - for (TransportProtos.ServiceInfo coreService : tbCoreServices) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); - producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); - toCoreNfs.incrementAndGet(); - } - } else { - Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); - ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); - for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { - TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); - if (tenantId.equals(queue.getTenantId())) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); - producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); - toRuleEngineNfs.incrementAndGet(); - } - } - } + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + doSendQueueNotifications(transportMsg, coreMsg, ruleEngineMsg); } @Override - public void onQueueDelete(Queue queue, TbQueueCallback callback) { + public void onQueueDelete(Queue queue) { log.trace("[{}][{}] Processing queue delete [{}] event", queue.getTenantId(), queue.getId(), queue.getName()); TransportProtos.QueueDeleteMsg queueDeleteMsg = TransportProtos.QueueDeleteMsg.newBuilder() @@ -545,33 +521,32 @@ public class DefaultTbClusterService implements TbClusterService { .setQueueName(queue.getName()) .build(); - if ("Main".equals(queue.getName())) { - Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); - for (TransportProtos.ServiceInfo transportService : tbTransportServices) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); - producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), callback); - toTransportNfs.incrementAndGet(); - } + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + doSendQueueNotifications(transportMsg, coreMsg, ruleEngineMsg); + } - Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); - ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); - for (TransportProtos.ServiceInfo coreService : tbCoreServices) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); - producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), callback); - toCoreNfs.incrementAndGet(); - } - } else { - Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); - ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); - for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { - TenantId tenantId = new TenantId(new UUID(ruleEngineService.getTenantIdMSB(), ruleEngineService.getTenantIdLSB())); - if (tenantId.equals(queue.getTenantId())) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); - producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), callback); - toRuleEngineNfs.incrementAndGet(); - } - } + private void doSendQueueNotifications(ToTransportMsg transportMsg, ToCoreNotificationMsg coreMsg, ToRuleEngineNotificationMsg ruleEngineMsg) { + Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); + for (TransportProtos.ServiceInfo transportService : tbTransportServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); + producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), null); + toTransportNfs.incrementAndGet(); + } + + Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); + for (TransportProtos.ServiceInfo coreService : tbCoreServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); + producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), null); + toCoreNfs.incrementAndGet(); + } + + Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); + for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); + producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), null); + toRuleEngineNfs.incrementAndGet(); } } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 4f5974457a..3f8173b9ac 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -30,7 +30,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.RuleNodeInfo; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -46,6 +45,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotifica import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.QueueKey; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; @@ -105,11 +105,11 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< private final PartitionService partitionService; private final TbServiceInfoProvider serviceInfoProvider; private final QueueService queueService; - private final TenantId tenantId; - private final ConcurrentMap>> consumers = new ConcurrentHashMap<>(); - private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>(); - private final ConcurrentMap consumerStats = new ConcurrentHashMap<>(); - private final ConcurrentMap topicsConsumerPerPartition = new ConcurrentHashMap<>(); + // private final TenantId tenantId; + private final ConcurrentMap>> consumers = new ConcurrentHashMap<>(); + private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>(); + private final ConcurrentMap consumerStats = new ConcurrentHashMap<>(); + private final ConcurrentMap topicsConsumerPerPartition = new ConcurrentHashMap<>(); final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); final ScheduledExecutorService repartitionExecutor = Executors.newScheduledThreadPool(1, ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-repartition")); @@ -135,25 +135,26 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.queueService = queueService; - this.tenantId = actorContext.getServiceInfoProvider().getIsolatedTenant().orElse(TenantId.SYS_TENANT_ID); +// this.tenantId = actorContext.getServiceInfoProvider().getIsolatedTenant().orElse(TenantId.SYS_TENANT_ID); } @PostConstruct public void init() { super.init("tb-rule-engine-consumer", "tb-rule-engine-notifications-consumer"); - List queues = queueService.findQueuesByTenantId(tenantId); + List queues = queueService.findAllQueues(); for (Queue configuration : queues) { initConsumer(configuration); } } private void initConsumer(Queue configuration) { - consumerConfigurations.putIfAbsent(configuration.getName(), configuration); - consumerStats.putIfAbsent(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName(), statsFactory)); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, configuration); + consumerConfigurations.putIfAbsent(queueKey, configuration); + consumerStats.putIfAbsent(queueKey, new TbRuleEngineConsumerStats(configuration.getName(), statsFactory)); if (!configuration.isConsumerPerPartition()) { - consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); + consumers.computeIfAbsent(queueKey, queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); } else { - topicsConsumerPerPartition.computeIfAbsent(configuration.getName(), TbTopicWithConsumerPerPartition::new); + topicsConsumerPerPartition.computeIfAbsent(queueKey, k -> new TbTopicWithConsumerPerPartition(k.getQueueName())); } } @@ -167,31 +168,31 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @Override protected void onTbApplicationEvent(PartitionChangeEvent event) { if (event.getServiceType().equals(getServiceType())) { - ServiceQueue serviceQueue = event.getServiceQueueKey().getServiceQueue(); - log.info("[{}] Subscribing to partitions: {}", serviceQueue.getQueue(), event.getPartitions()); - if (!consumerConfigurations.get(serviceQueue.getQueue()).isConsumerPerPartition()) { - consumers.get(serviceQueue.getQueue()).subscribe(event.getPartitions()); + String serviceQueue = event.getQueueKey().getQueueName(); + log.info("[{}] Subscribing to partitions: {}", serviceQueue, event.getPartitions()); + if (!consumerConfigurations.get(event.getQueueKey()).isConsumerPerPartition()) { + consumers.get(event.getQueueKey()).subscribe(event.getPartitions()); } else { - log.info("[{}] Subscribing consumer per partition: {}", serviceQueue.getQueue(), event.getPartitions()); - subscribeConsumerPerPartition(serviceQueue.getQueue(), event.getPartitions()); + log.info("[{}] Subscribing consumer per partition: {}", serviceQueue, event.getPartitions()); + subscribeConsumerPerPartition(event.getQueueKey(), event.getPartitions()); } } } - void subscribeConsumerPerPartition(String queue, Set partitions) { + void subscribeConsumerPerPartition(QueueKey queue, Set partitions) { topicsConsumerPerPartition.get(queue).getSubscribeQueue().add(partitions); scheduleTopicRepartition(queue); } - private void scheduleTopicRepartition(String queue) { + private void scheduleTopicRepartition(QueueKey queue) { repartitionExecutor.schedule(() -> repartitionTopicWithConsumerPerPartition(queue), 1, TimeUnit.SECONDS); } - void repartitionTopicWithConsumerPerPartition(final String queueName) { + void repartitionTopicWithConsumerPerPartition(final QueueKey queueKey) { if (stopped) { return; } - TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueName); + TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueKey); java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); if (subscribeQueue.isEmpty()) { return; @@ -216,15 +217,15 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< log.info("calculated removedPartitions {}", removedPartitions); removedPartitions.forEach((tpi) -> { - removeConsumerForTopicByTpi(queueName, consumers, tpi); + removeConsumerForTopicByTpi(queueKey.getQueueName(), consumers, tpi); }); addedPartitions.forEach((tpi) -> { - log.info("[{}] Adding consumer for topic: {}", queueName, tpi); - Queue configuration = consumerConfigurations.get(queueName); + log.info("[{}] Adding consumer for topic: {}", queueKey, tpi); + Queue configuration = consumerConfigurations.get(queueKey); TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); consumers.put(tpi, consumer); - launchConsumer(consumer, consumerConfigurations.get(queueName), consumerStats.get(queueName), "" + queueName + "-" + tpi.getPartition().orElse(-999999)); + launchConsumer(consumer, consumerConfigurations.get(queueKey), consumerStats.get(queueKey), "" + queueKey + "-" + tpi.getPartition().orElse(-999999)); consumer.subscribe(Collections.singleton(tpi)); }); @@ -232,7 +233,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< tbTopicWithConsumerPerPartition.getLock().unlock(); } } else { - scheduleTopicRepartition(queueName); //reschedule later + scheduleTopicRepartition(queueKey); //reschedule later } } @@ -245,7 +246,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @Override protected void launchMainConsumers() { - consumers.forEach((queue, consumer) -> launchConsumer(consumer, consumerConfigurations.get(queue), consumerStats.get(queue), queue)); + consumers.forEach((queue, consumer) -> launchConsumer(consumer, consumerConfigurations.get(queue), consumerStats.get(queue), queue.getQueueName())); } @Override @@ -408,11 +409,14 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< private void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { String queueName = queueUpdateMsg.getQueueName(); - Queue queue = queueService.findQueueByTenantIdAndName(tenantId, queueName); - Queue oldQueue = consumerConfigurations.remove(queueName); + TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); + QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName(), tenantId); + Queue queue = queueService.findQueueById(tenantId, queueId); + Queue oldQueue = consumerConfigurations.remove(queueKey); if (oldQueue != null) { if (oldQueue.isConsumerPerPartition()) { - TbTopicWithConsumerPerPartition consumerPerPartition = topicsConsumerPerPartition.remove(queueName); + TbTopicWithConsumerPerPartition consumerPerPartition = topicsConsumerPerPartition.remove(queueKey); ReentrantLock lock = consumerPerPartition.getLock(); try { lock.lock(); @@ -421,7 +425,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< lock.unlock(); } } else { - TbQueueConsumer> consumer = consumers.remove(queueName); + TbQueueConsumer> consumer = consumers.remove(queueKey); consumer.unsubscribe(); } } @@ -429,7 +433,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< initConsumer(queue); if (!queue.isConsumerPerPartition()) { - launchConsumer(consumers.get(queueName), consumerConfigurations.get(queueName), consumerStats.get(queueName), queueName); + launchConsumer(consumers.get(queueKey), consumerConfigurations.get(queueKey), consumerStats.get(queueKey), queueName); } partitionService.updateQueue(queueUpdateMsg); @@ -437,16 +441,19 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } private void deleteQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { - Queue queue = consumerConfigurations.remove(queueDeleteMsg.getQueueName()); + TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); + + Queue queue = consumerConfigurations.remove(queueKey); if (queue != null) { if (queue.isConsumerPerPartition()) { - TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.remove(queueDeleteMsg.getQueueName()); + TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.remove(queueKey); if (tbTopicWithConsumerPerPartition != null) { tbTopicWithConsumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe); tbTopicWithConsumerPerPartition.getConsumers().clear(); } } else { - TbQueueConsumer> consumer = consumers.remove(queueDeleteMsg.getQueueName()); + TbQueueConsumer> consumer = consumers.remove(queueKey); if (consumer != null) { consumer.unsubscribe(); } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index eaa76d4273..658a403654 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1094,7 +1094,6 @@ service: type: "${TB_SERVICE_TYPE:monolith}" # monolith or tb-core or tb-rule-engine # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" - tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. metrics: # Enable/disable actuator metrics. diff --git a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java index 0c13157623..c8fb678470 100644 --- a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java @@ -74,8 +74,8 @@ public class HashPartitionServiceTest { ReflectionTestUtils.setField(clusterRoutingService, "hashFunctionName", hashFunctionName); TransportProtos.ServiceInfo currentServer = TransportProtos.ServiceInfo.newBuilder() .setServiceId("tb-core-0") - .setTenantIdMSB(TenantId.NULL_UUID.getMostSignificantBits()) - .setTenantIdLSB(TenantId.NULL_UUID.getLeastSignificantBits()) +// .setTenantIdMSB(TenantId.NULL_UUID.getMostSignificantBits()) +// .setTenantIdLSB(TenantId.NULL_UUID.getLeastSignificantBits()) .addAllServiceTypes(Collections.singletonList(ServiceType.TB_CORE.name())) .build(); // when(queueService.resolve(Mockito.any(), Mockito.anyString())).thenAnswer(i -> i.getArguments()[1]); @@ -84,8 +84,8 @@ public class HashPartitionServiceTest { for (int i = 1; i < SERVER_COUNT; i++) { otherServers.add(TransportProtos.ServiceInfo.newBuilder() .setServiceId("tb-rule-" + i) - .setTenantIdMSB(TenantId.NULL_UUID.getMostSignificantBits()) - .setTenantIdLSB(TenantId.NULL_UUID.getLeastSignificantBits()) +// .setTenantIdMSB(TenantId.NULL_UUID.getMostSignificantBits()) +// .setTenantIdLSB(TenantId.NULL_UUID.getLeastSignificantBits()) .addAllServiceTypes(Collections.singletonList(ServiceType.TB_CORE.name())) .build()); } diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java index d37760211f..068304df1f 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueClusterService.java @@ -18,7 +18,7 @@ package org.thingsboard.server.queue; import org.thingsboard.server.common.data.queue.Queue; public interface TbQueueClusterService { - void onQueueChange(Queue queue, TbQueueCallback callback); + void onQueueChange(Queue queue); - void onQueueDelete(Queue queue, TbQueueCallback callback); + void onQueueDelete(Queue queue); } diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 8b4164e30f..32bcfd688d 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -32,8 +32,8 @@ option java_outer_classname = "TransportProtos"; message ServiceInfo { string serviceId = 1; repeated string serviceTypes = 2; - int64 tenantIdMSB = 3; - int64 tenantIdLSB = 4; +// int64 tenantIdMSB = 3; +// int64 tenantIdLSB = 4; // repeated QueueInfo ruleEngineQueues = 5; repeated string transports = 6; } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java index edb51fa2a3..3fbb228f3c 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java @@ -30,12 +30,12 @@ public interface QueueService { void deleteQueue(TenantId tenantId, QueueId queueId); + void deleteQueueByQueueName(TenantId tenantId, String queueName); + List findQueuesByTenantId(TenantId tenantId); PageData findQueuesByTenantId(TenantId tenantId, PageLink pageLink); - List findAllMainQueues(); - List findAllQueues(); Queue findQueueById(TenantId tenantId, QueueId queueId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java index 004bd0057d..90caa9c03f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; @Data public class Queue extends BaseData implements HasName, HasTenantId { @@ -40,4 +41,16 @@ public class Queue extends BaseData implements HasName, HasTenantId { public Queue(QueueId id) { super(id); } + + public Queue(TenantId tenantId, TenantProfileQueueConfiguration queueConfiguration) { + this.tenantId = tenantId; + this.name = queueConfiguration.getName(); + this.topic = queueConfiguration.getTopic(); + this.pollInterval = queueConfiguration.getPollInterval(); + this.partitions = queueConfiguration.getPartitions(); + this.consumerPerPartition = queueConfiguration.isConsumerPerPartition(); + this.packProcessingTimeout = queueConfiguration.getPackProcessingTimeout(); + this.submitStrategy = queueConfiguration.getSubmitStrategy(); + this.processingStrategy = queueConfiguration.getProcessingStrategy(); + } } \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java index 8427a6ca78..78b6d9ae3c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileData.java @@ -19,6 +19,8 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import java.util.List; + @ApiModel @Data public class TenantProfileData { @@ -26,4 +28,7 @@ public class TenantProfileData { @ApiModelProperty(position = 1, value = "Complex JSON object that contains profile settings: max devices, max assets, rate limits, etc.") private TenantProfileConfiguration configuration; + @ApiModelProperty(position = 2, value = "JSON array of queue configuration per tenant profile") + private List queueConfiguration; + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileQueueConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileQueueConfiguration.java new file mode 100644 index 0000000000..8d3389af3a --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileQueueConfiguration.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.tenant.profile; + +import lombok.Data; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategy; + +@Data +public class TenantProfileQueueConfiguration { + private String name; + private String topic; + private int pollInterval; + private int partitions; + private boolean consumerPerPartition; + private long packProcessingTimeout; + private SubmitStrategy submitStrategy; + private ProcessingStrategy processingStrategy; +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java index 3a2fdbd187..4917444e2d 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java @@ -29,7 +29,7 @@ import java.util.Set; public final class PartitionChangeMsg implements TbActorMsg { @Getter - private final ServiceQueueKey serviceQueueKey; + private final ServiceType serviceType; @Getter private final Set partitions; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java index 1701221c0e..f47f5ab8b1 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java @@ -17,7 +17,6 @@ package org.thingsboard.server.common.msg.queue; import lombok.Getter; import lombok.ToString; -import org.thingsboard.server.common.data.id.TenantId; import java.util.Objects; @@ -26,12 +25,8 @@ public class ServiceQueueKey { @Getter private final ServiceQueue serviceQueue; - @Getter - private final TenantId tenantId; - - public ServiceQueueKey(ServiceQueue serviceQueue, TenantId tenantId) { + public ServiceQueueKey(ServiceQueue serviceQueue) { this.serviceQueue = serviceQueue; - this.tenantId = tenantId; } @Override @@ -39,16 +34,15 @@ public class ServiceQueueKey { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ServiceQueueKey that = (ServiceQueueKey) o; - return serviceQueue.equals(that.serviceQueue) && - Objects.equals(tenantId, that.tenantId); + return serviceQueue.equals(that.serviceQueue); } @Override public int hashCode() { - return Objects.hash(serviceQueue, tenantId); + return Objects.hash(serviceQueue); } public ServiceType getServiceType() { return serviceQueue.getType(); } -} +} \ No newline at end of file diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java index 62e9852dd1..78ed1175ba 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java @@ -23,10 +23,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.TbTransportService; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; -import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.util.AfterContextReady; import javax.annotation.PostConstruct; @@ -36,8 +34,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Optional; -import java.util.UUID; import java.util.stream.Collectors; @Component @@ -56,14 +52,11 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { @Value("${service.tenant_id:}") private String tenantIdStr; - @Autowired(required = false) - private TbQueueRuleEngineSettings ruleEngineSettings; @Autowired private ApplicationContext applicationContext; private List serviceTypes; private ServiceInfo serviceInfo; - private TenantId isolatedTenant; @PostConstruct public void init() { @@ -83,15 +76,6 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { ServiceInfo.Builder builder = ServiceInfo.newBuilder() .setServiceId(serviceId) .addAllServiceTypes(serviceTypes.stream().map(ServiceType::name).collect(Collectors.toList())); - UUID tenantId; - if (!StringUtils.isEmpty(tenantIdStr)) { - tenantId = UUID.fromString(tenantIdStr); - isolatedTenant = TenantId.fromUUID(tenantId); - } else { - tenantId = TenantId.NULL_UUID; - } - builder.setTenantIdMSB(tenantId.getMostSignificantBits()); - builder.setTenantIdLSB(tenantId.getLeastSignificantBits()); serviceInfo = builder.build(); } @@ -119,8 +103,4 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { return serviceTypes.contains(serviceType); } - @Override - public Optional getIsolatedTenant() { - return Optional.ofNullable(isolatedTenant); - } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index ce7c93741a..861f7b657e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -63,13 +63,15 @@ public class HashPartitionService implements PartitionService { private final TbServiceInfoProvider serviceInfoProvider; private final TenantRoutingInfoService tenantRoutingInfoService; private final QueueRoutingInfoService queueRoutingInfoService; - private final ConcurrentMap queueNames = new ConcurrentHashMap<>(); - private final ConcurrentMap> partitionTopicsMap = new ConcurrentHashMap<>(); - private final ConcurrentMap> partitionSizesMap = new ConcurrentHashMap<>(); - private final ConcurrentMap tenantRoutingInfoMap = new ConcurrentHashMap<>(); - private ConcurrentMap> myPartitions = new ConcurrentHashMap<>(); - private ConcurrentMap tpiCache = new ConcurrentHashMap<>(); + private final ConcurrentMap queuesById = new ConcurrentHashMap<>(); + + private ConcurrentMap> myPartitions = new ConcurrentHashMap<>(); + + private final ConcurrentMap partitionTopicsMap = new ConcurrentHashMap<>(); + private final ConcurrentMap partitionSizesMap = new ConcurrentHashMap<>(); + + private final ConcurrentMap tenantRoutingInfoMap = new ConcurrentHashMap<>(); private Map> tbTransportServicesByType = new HashMap<>(); private List currentOtherServices; @@ -93,8 +95,9 @@ public class HashPartitionService implements PartitionService { } private void partitionsInit() { - addPartitionSizeToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE), corePartitions); - addPartitionTopicToMap(TenantId.SYS_TENANT_ID, new ServiceQueue(ServiceType.TB_CORE), coreTopic); + QueueKey coreKey = new QueueKey(ServiceType.TB_CORE); + partitionSizesMap.put(coreKey, corePartitions); + partitionTopicsMap.put(coreKey, coreTopic); List queueRoutingInfoList; @@ -127,69 +130,59 @@ public class HashPartitionService implements PartitionService { } queueRoutingInfoList.forEach(queue -> { - addPartitionTopicToMap(queue.getTenantId(), new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getQueueName()), queue.getQueueTopic()); - addPartitionSizeToMap(queue.getTenantId(), new ServiceQueue(ServiceType.TB_RULE_ENGINE, queue.getQueueName()), queue.getPartitions()); - queueNames.put(queue.getQueueId(), queue.getQueueName()); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queue); + partitionTopicsMap.put(queueKey, queue.getQueueTopic()); + partitionSizesMap.put(queueKey, queue.getPartitions()); + queuesById.put(queue.getQueueId(), queue); }); } @Override public void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); - addPartitionTopicToMap(tenantId, new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName()), queueUpdateMsg.getQueueTopic()); - addPartitionSizeToMap(tenantId, new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName()), queueUpdateMsg.getPartitions()); - queueNames.putIfAbsent(new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())), queueUpdateMsg.getQueueName()); - tpiCache.clear(); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName(), tenantId); + partitionTopicsMap.put(queueKey, queueUpdateMsg.getQueueTopic()); + partitionSizesMap.put(queueKey, queueUpdateMsg.getPartitions()); + QueueRoutingInfo queue = new QueueRoutingInfo(queueUpdateMsg); + queuesById.put(queue.getQueueId(), queue); } @Override public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); - ServiceQueue serviceQueue = new ServiceQueue(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName()); - partitionTopicsMap.get(tenantId).remove(serviceQueue); - partitionSizesMap.get(tenantId).remove(serviceQueue); - myPartitions.remove(new ServiceQueueKey(serviceQueue, tenantId)); - queueNames.remove(new QueueId(new UUID(queueDeleteMsg.getQueueIdMSB(), queueDeleteMsg.getQueueIdLSB()))); - tpiCache.clear(); - } - - private void addPartitionSizeToMap(TenantId tenantId, ServiceQueue serviceQueue, int partitions) { - partitionSizesMap.computeIfAbsent(tenantId, id -> new ConcurrentHashMap<>()).put(serviceQueue, partitions); - } - - private void addPartitionTopicToMap(TenantId tenantId, ServiceQueue serviceQueue, String topic) { - partitionTopicsMap.computeIfAbsent(tenantId, id -> new ConcurrentHashMap<>()).put(serviceQueue, topic); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); + partitionTopicsMap.remove(queueKey); + partitionSizesMap.remove(queueKey); + queuesById.remove(new QueueId(new UUID(queueDeleteMsg.getQueueIdMSB(), queueDeleteMsg.getQueueIdLSB()))); + myPartitions.remove(queueKey); } @Override public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) { - return resolve(new ServiceQueue(serviceType), tenantId, entityId); + return resolve(serviceType, null, tenantId, entityId); } @Override public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) { - String queueName; + QueueKey queueKey; if (queueId == null) { - queueName = ServiceQueue.MAIN; + queueKey = isIsolated(serviceType, tenantId) ? new QueueKey(serviceType, tenantId) : new QueueKey(serviceType); } else { - queueName = queueNames.get(queueId); + queueKey = new QueueKey(serviceType, queuesById.get(queueId)); } - ServiceQueue serviceQueue = new ServiceQueue(serviceType, queueName); - return resolve(serviceQueue, tenantId, entityId); + return resolve(queueKey, entityId); } - private TopicPartitionInfo resolve(ServiceQueue serviceQueue, TenantId tenantId, EntityId entityId) { + private TopicPartitionInfo resolve(QueueKey queueKey, EntityId entityId) { int hash = hashFunction.newHasher() .putLong(entityId.getId().getMostSignificantBits()) .putLong(entityId.getId().getLeastSignificantBits()).hash().asInt(); - boolean isolatedTenant = isIsolated(serviceQueue.getType(), tenantId); - Integer partitionSize = partitionSizesMap.get(isolatedTenant ? tenantId : TenantId.SYS_TENANT_ID).get(serviceQueue); + Integer partitionSize = partitionSizesMap.get(queueKey); int partition = Math.abs(hash % partitionSize); - TopicPartitionInfoKey cacheKey = new TopicPartitionInfoKey(serviceQueue, isolatedTenant ? tenantId : null, partition); - return tpiCache.computeIfAbsent(cacheKey, key -> buildTopicPartitionInfo(serviceQueue, tenantId, partition)); + return buildTopicPartitionInfo(queueKey, partition); } @Override @@ -197,43 +190,39 @@ public class HashPartitionService implements PartitionService { tbTransportServicesByType.clear(); logServiceInfo(currentService); otherServices.forEach(this::logServiceInfo); - Map> queueServicesMap = new HashMap<>(); + + Map> queueServicesMap = new HashMap<>(); addNode(queueServicesMap, currentService); for (ServiceInfo other : otherServices) { addNode(queueServicesMap, other); } queueServicesMap.values().forEach(list -> list.sort(Comparator.comparing(ServiceInfo::getServiceId))); - ConcurrentMap> oldPartitions = myPartitions; - TenantId myIsolatedOrSystemTenantId = getSystemOrIsolatedTenantId(currentService); + ConcurrentMap> oldPartitions = myPartitions; myPartitions = new ConcurrentHashMap<>(); - partitionSizesMap.get(myIsolatedOrSystemTenantId).forEach((serviceQueue, size) -> { - ServiceQueueKey myServiceQueueKey = new ServiceQueueKey(serviceQueue, myIsolatedOrSystemTenantId); + partitionSizesMap.forEach((queueKey, size) -> { for (int i = 0; i < size; i++) { - ServiceInfo serviceInfo = resolveByPartitionIdx(queueServicesMap.get(myServiceQueueKey), i); + ServiceInfo serviceInfo = resolveByPartitionIdx(queueServicesMap.get(queueKey), i); if (currentService.equals(serviceInfo)) { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(serviceQueue, getSystemOrIsolatedTenantId(serviceInfo)); - myPartitions.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(i); + myPartitions.computeIfAbsent(queueKey, key -> new ArrayList<>()).add(i); } } }); - tpiCache.clear(); - - oldPartitions.forEach((serviceQueueKey, partitions) -> { - if (!myPartitions.containsKey(serviceQueueKey)) { - log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", serviceQueueKey); - applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceQueueKey, Collections.emptySet())); + oldPartitions.forEach((queueKey, partitions) -> { + if (!myPartitions.containsKey(queueKey)) { + log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", queueKey); + applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, queueKey, Collections.emptySet())); } }); - myPartitions.forEach((serviceQueueKey, partitions) -> { - if (!partitions.equals(oldPartitions.get(serviceQueueKey))) { - log.info("[{}] NEW PARTITIONS: {}", serviceQueueKey, partitions); + myPartitions.forEach((queueKey, partitions) -> { + if (!partitions.equals(oldPartitions.get(queueKey))) { + log.info("[{}] NEW PARTITIONS: {}", queueKey, partitions); Set tpiList = partitions.stream() - .map(partition -> buildTopicPartitionInfo(serviceQueueKey, partition)) + .map(partition -> buildTopicPartitionInfo(queueKey, partition)) .collect(Collectors.toSet()); - applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceQueueKey, tpiList)); + applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, queueKey, tpiList)); } }); @@ -313,7 +302,7 @@ public class HashPartitionService implements PartitionService { // currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); // } } else { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType), getSystemOrIsolatedTenantId(serviceInfo)); + ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType)); currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); } } @@ -321,24 +310,13 @@ public class HashPartitionService implements PartitionService { return currentMap; } - private TopicPartitionInfo buildTopicPartitionInfo(ServiceQueueKey serviceQueueKey, int partition) { - return buildTopicPartitionInfo(serviceQueueKey.getServiceQueue(), serviceQueueKey.getTenantId(), partition); - } - - private TopicPartitionInfo buildTopicPartitionInfo(ServiceQueue serviceQueue, TenantId tenantId, int partition) { - boolean isolatedTenant = isIsolated(serviceQueue.getType(), tenantId); - + private TopicPartitionInfo buildTopicPartitionInfo(QueueKey queueKey, int partition) { TopicPartitionInfo.TopicPartitionInfoBuilder tpi = TopicPartitionInfo.builder(); - tpi.topic(partitionTopicsMap.get(isolatedTenant ? tenantId : TenantId.SYS_TENANT_ID).get(serviceQueue)); + tpi.topic(partitionTopicsMap.get(queueKey)); tpi.partition(partition); - ServiceQueueKey myPartitionsSearchKey; - if (isolatedTenant) { - tpi.tenantId(tenantId); - myPartitionsSearchKey = new ServiceQueueKey(serviceQueue, tenantId); - } else { - myPartitionsSearchKey = new ServiceQueueKey(serviceQueue, TenantId.SYS_TENANT_ID); - } - List partitions = myPartitions.get(myPartitionsSearchKey); + tpi.tenantId(queueKey.getTenantId()); + + List partitions = myPartitions.get(queueKey); if (partitions != null) { tpi.myPartition(partitions.contains(partition)); } else { @@ -374,39 +352,24 @@ public class HashPartitionService implements PartitionService { } } - private TenantId getSystemIsolatedTenantId(ServiceType serviceType, TenantId tenantId) { - return isIsolated(serviceType, tenantId) ? tenantId : TenantId.SYS_TENANT_ID; - } - private void logServiceInfo(TransportProtos.ServiceInfo server) { - TenantId tenantId = getSystemOrIsolatedTenantId(server); - if (tenantId.isNullUid()) { - log.info("[{}] Found common server: [{}]", server.getServiceId(), server.getServiceTypesList()); - } else { - log.info("[{}][{}] Found specific server: [{}]", server.getServiceId(), tenantId, server.getServiceTypesList()); - } + log.info("[{}] Found common server: [{}]", server.getServiceId(), server.getServiceTypesList()); } - private TenantId getSystemOrIsolatedTenantId(TransportProtos.ServiceInfo serviceInfo) { - return TenantId.fromUUID(new UUID(serviceInfo.getTenantIdMSB(), serviceInfo.getTenantIdLSB())); - } - - private void addNode(Map> queueServiceList, ServiceInfo instance) { - TenantId tenantId = getSystemOrIsolatedTenantId(instance); + private void addNode(Map> queueServiceList, ServiceInfo instance) { for (String serviceTypeStr : instance.getServiceTypesList()) { ServiceType serviceType = ServiceType.valueOf(serviceTypeStr.toUpperCase()); if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) { - partitionTopicsMap.get(tenantId).forEach((serviceQueue, topic) -> { - if (serviceQueue.getType().equals(ServiceType.TB_RULE_ENGINE)) { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(serviceQueue, tenantId); - queueServiceList.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(instance); + partitionTopicsMap.keySet().forEach(key -> { + if (key.getType().equals(ServiceType.TB_RULE_ENGINE)) { + queueServiceList.computeIfAbsent(key, k -> new ArrayList<>()).add(instance); } }); - } else { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType), tenantId); - queueServiceList.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(instance); + } else if (ServiceType.TB_CORE.equals(serviceType)) { + queueServiceList.computeIfAbsent(new QueueKey(serviceType), key -> new ArrayList<>()).add(instance); } } + for (String transportType : instance.getTransportsList()) { tbTransportServicesByType.computeIfAbsent(transportType, t -> new ArrayList<>()).add(instance); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueKey.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueKey.java new file mode 100644 index 0000000000..a2d5982421 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueKey.java @@ -0,0 +1,56 @@ +/** + * 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.queue.discovery; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.queue.ServiceType; + +@Data +@AllArgsConstructor +public class QueueKey { + private static final String MAIN = "Main"; + + private final ServiceType type; + private final String queueName; + private final TenantId tenantId; + + public QueueKey(ServiceType type, Queue queue) { + this.type = type; + this.queueName = queue.getName(); + this.tenantId = queue.getTenantId(); + } + + public QueueKey(ServiceType type, QueueRoutingInfo queueRoutingInfo) { + this.type = type; + this.queueName = queueRoutingInfo.getQueueName(); + this.tenantId = queueRoutingInfo.getTenantId(); + } + + public QueueKey(ServiceType type, TenantId tenantId) { + this.type = type; + this.queueName = MAIN; + this.tenantId = tenantId != null ? tenantId : TenantId.SYS_TENANT_ID; + } + + public QueueKey(ServiceType type) { + this.type = type; + this.queueName = MAIN; + this.tenantId = TenantId.SYS_TENANT_ID; + } +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java index 111ca5626a..7e80ebc048 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/QueueRoutingInfo.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.gen.transport.TransportProtos.GetQueueRoutingInfoResponseMsg; +import org.thingsboard.server.gen.transport.TransportProtos.QueueUpdateMsg; import java.util.UUID; @@ -48,4 +49,12 @@ public class QueueRoutingInfo { this.queueTopic = routingInfo.getQueueTopic(); this.partitions = routingInfo.getPartitions(); } + + public QueueRoutingInfo(QueueUpdateMsg queueUpdateMsg) { + this.tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getQueueIdLSB())); + this.queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())); + this.queueName = queueUpdateMsg.getQueueName(); + this.queueTopic = queueUpdateMsg.getQueueTopic(); + this.partitions = queueUpdateMsg.getPartitions(); + } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java index 8e73c23c7e..2e88e34425 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbServiceInfoProvider.java @@ -15,12 +15,9 @@ */ package org.thingsboard.server.queue.discovery; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; -import java.util.Optional; - public interface TbServiceInfoProvider { String getServiceId(); @@ -31,6 +28,4 @@ public interface TbServiceInfoProvider { boolean isService(ServiceType serviceType); - Optional getIsolatedTenant(); - } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TopicPartitionInfoKey.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TopicPartitionInfoKey.java deleted file mode 100644 index 86cddf2119..0000000000 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/TopicPartitionInfoKey.java +++ /dev/null @@ -1,44 +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.queue.discovery; - -import lombok.AllArgsConstructor; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.msg.queue.ServiceQueue; - -import java.util.Objects; - -@AllArgsConstructor -public class TopicPartitionInfoKey { - private ServiceQueue serviceQueue; - private TenantId isolatedTenantId; - private int partition; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TopicPartitionInfoKey that = (TopicPartitionInfoKey) o; - return partition == that.partition && - serviceQueue.equals(that.serviceQueue) && - Objects.equals(isolatedTenantId, that.isolatedTenantId); - } - - @Override - public int hashCode() { - return Objects.hash(serviceQueue, isolatedTenantId, partition); - } -} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java index 342f7596eb..a6335fb4da 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java @@ -17,9 +17,9 @@ package org.thingsboard.server.queue.discovery.event; import lombok.Getter; import lombok.ToString; -import org.thingsboard.server.common.msg.queue.ServiceQueueKey; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.queue.discovery.QueueKey; import java.util.Set; @@ -29,17 +29,17 @@ public class PartitionChangeEvent extends TbApplicationEvent { private static final long serialVersionUID = -8731788167026510559L; @Getter - private final ServiceQueueKey serviceQueueKey; + private final QueueKey queueKey; @Getter private final Set partitions; - public PartitionChangeEvent(Object source, ServiceQueueKey serviceQueueKey, Set partitions) { + public PartitionChangeEvent(Object source, QueueKey queueKey, Set partitions) { super(source); - this.serviceQueueKey = serviceQueueKey; + this.queueKey = queueKey; this.partitions = partitions; } public ServiceType getServiceType() { - return serviceQueueKey.getServiceQueue().getType(); + return queueKey.getType(); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index e2fd459189..28c0330267 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -87,7 +87,7 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ } if (queueClusterService != null) { - queueClusterService.onQueueChange(createdQueue, null); + queueClusterService.onQueueChange(createdQueue); } return createdQueue; @@ -107,12 +107,12 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } if (queueClusterService != null) { - queueClusterService.onQueueChange(updatedQueue, null); + queueClusterService.onQueueChange(updatedQueue); } } else { log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); if (queueClusterService != null) { - queueClusterService.onQueueChange(updatedQueue, null); + queueClusterService.onQueueChange(updatedQueue); } await(); for (int i = currentPartitions; i < oldPartitions; i++) { @@ -120,7 +120,7 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ } } } else if (!oldQueue.equals(queue) && queueClusterService != null) { - queueClusterService.onQueueChange(updatedQueue, null); + queueClusterService.onQueueChange(updatedQueue); } return updatedQueue; @@ -130,12 +130,23 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ public void deleteQueue(TenantId tenantId, QueueId queueId) { log.trace("Executing deleteQueue, queueId: [{}]", queueId); Queue queue = findQueueById(tenantId, queueId); + doDelete(tenantId, queue); + } + + @Override + public void deleteQueueByQueueName(TenantId tenantId, String queueName) { + log.trace("Executing deleteQueueByQueueName, name: [{}]", queueName); + Queue queue = findQueueByTenantIdAndName(tenantId, queueName); + doDelete(tenantId, queue); + } + + private void doDelete(TenantId tenantId, Queue queue) { if (queueClusterService != null) { - queueClusterService.onQueueDelete(queue, null); + queueClusterService.onQueueDelete(queue); await(); } // queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); - boolean result = queueDao.removeById(tenantId, queueId.getId()); + boolean result = queueDao.removeById(tenantId, queue.getUuidId()); if (result && tbQueueAdmin != null) { for (int i = 0; i < queue.getPartitions(); i++) { String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); @@ -167,12 +178,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ return queueDao.findQueuesByTenantId(getSystemOrIsolatedTenantId(tenantId), pageLink); } - @Override - public List findAllMainQueues() { - log.trace("Executing findAllMainQueues"); - return queueDao.findAllMainQueues(); - } - @Override public List findAllQueues() { log.trace("Executing findAllQueues"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index b8d0f1f84b..4b935ca700 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -24,10 +24,11 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; @@ -48,6 +49,12 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.widget.WidgetsBundleService; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import static org.thingsboard.server.dao.service.Validator.validateId; @Service @@ -138,18 +145,90 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe tenant.setTenantProfileId(tenantProfile.getId()); } tenantValidator.validate(tenant, Tenant::getId); + + Tenant oldTenant = tenant.getId() != null ? tenantDao.findById(tenant.getId(), tenant.getUuidId()) : null; + Tenant savedTenant = tenantDao.save(tenant.getId(), tenant); if (tenant.getId() == null) { deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); - TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId()); - if(tenantProfile.isIsolatedTbRuleEngine()) { - queueService.createDefaultMainQueue(tenantProfile, savedTenant.getTenantId()); - } } + + updateQueuesForTenant(oldTenant, savedTenant); + return savedTenant; } + private void updateQueuesForTenant(Tenant oldTenant, Tenant newTenant) { + TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; + TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, newTenant.getTenantProfileId()); + + TenantId tenantId = newTenant.getId(); + + boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); + boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); + + if (!oldIsolated && !newIsolated) { + return; + } + + if (newTenantProfile.equals(oldTenantProfile)) { + return; + } + + Map oldQueues; + Map newQueues; + + if (oldIsolated) { + oldQueues = oldTenantProfile.getProfileData().getQueueConfiguration().stream() + .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); + } else { + oldQueues = Collections.emptyMap(); + } + + if (newIsolated) { + newQueues = newTenantProfile.getProfileData().getQueueConfiguration().stream() + .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); + } else { + newQueues = Collections.emptyMap(); + } + + List toRemove = new ArrayList<>(); + List toCreate = new ArrayList<>(); + List toUpdate = new ArrayList<>(); + + for (String oldQueue : oldQueues.keySet()) { + if (!newQueues.containsKey(oldQueue)) { + toRemove.add(oldQueue); + } + } + + for (String newQueue : newQueues.keySet()) { + if (oldQueues.containsKey(newQueue)) { + toUpdate.add(newQueue); + } else { + toCreate.add(newQueue); + } + } + + toRemove.forEach(q -> queueService.deleteQueueByQueueName(tenantId, q)); + + toCreate.forEach(key -> queueService.saveQueue(new Queue(tenantId, newQueues.get(key)))); + + toUpdate.forEach(key -> { + Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); + Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, key); + queueToUpdate.setId(foundQueue.getId()); + queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); + + if (queueToUpdate.equals(foundQueue)) { + //Queue not changed + } else { + queueService.saveQueue(queueToUpdate); + } + }); + } + @Override public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); @@ -218,7 +297,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private void validateTenantProfile(TenantId tenantId, Tenant tenant) { TenantProfile tenantProfileById = tenantProfileService.findTenantProfileById(tenantId, tenant.getTenantProfileId()); if (!zkEnabled && (tenantProfileById.isIsolatedTbCore() || tenantProfileById.isIsolatedTbRuleEngine())) { - throw new DataValidationException("Can't use isolated tenant profiles in monolith setup!"); +// throw new DataValidationException("Can't use isolated tenant profiles in monolith setup!"); } } }; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index 4a29787762..f08b9c06a0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -27,7 +27,6 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.session.SessionMsgType; import java.util.UUID; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index f8b4d64b42..1a26cf97ef 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import java.util.UUID; import java.util.concurrent.TimeUnit; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index 464acadb94..5a313da469 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.msg.queue.ServiceQueue; import java.util.HashMap; import java.util.Map; diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts index 2bddd229bc..78507cb121 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts @@ -567,7 +567,9 @@ export class ImportExportService { return isDefined(tenantProfile.name) && isDefined(tenantProfile.profileData) && isDefined(tenantProfile.isolatedTbCore) - && isDefined(tenantProfile.isolatedTbRuleEngine); + && isDefined(tenantProfile.isolatedTbRuleEngine) + && isDefined(tenantProfile.maxNumberOfQueues) + && isDefined(tenantProfile.maxNumberOfPartitionsPerQueue); } private sumObject(obj1: any, obj2: any): any { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index 03ff1ff921..6377e59a45 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -67,36 +67,38 @@
{{ 'tenant.isolated-tb-rule-engine' | translate }}
{{'tenant.isolated-tb-rule-engine-details' | translate}}
- - tenant.max-number-of-queues - - - {{ 'tenant.max-number-of-queues-required' | translate }} - - - {{ 'tenant.max-number-of-queues-min-length' | translate }} - - - - tenant.max-number-of-partitions-per-queue - - - {{ 'tenant.max-number-of-partitions-per-queue-required' | translate }} - - - {{ 'tenant.max-number-of-partitions-per-queue-min-length' | translate }} - - +
+ + tenant.max-number-of-queues + + + {{ 'tenant.max-number-of-queues-required' | translate }} + + + {{ 'tenant.max-number-of-queues-min-length' | translate }} + + + + tenant.max-number-of-partitions-per-queue + + + {{ 'tenant.max-number-of-partitions-per-queue-required' | translate }} + + + {{ 'tenant.max-number-of-partitions-per-queue-min-length' | translate }} + + +
{ super(store, fb, entityValue, entitiesTableConfigValue, cd); } + ngOnInit() { + this.showQueueParams(); + this.entityForm.get('isolatedTbRuleEngine').valueChanges.subscribe(() => this.showQueueParams()); + } + hideDelete() { if (this.entitiesTableConfig) { return !this.entitiesTableConfig.deleteEnabled(this.entity); @@ -87,11 +92,11 @@ export class TenantProfileComponent extends EntityComponent { showQueueParams(): boolean { let isolatedTbRuleEngine: boolean = this.entityForm.get('isolatedTbRuleEngine').value; if (isolatedTbRuleEngine) { - this.entityForm.controls['maxNumberOfQueues'].enable(); - this.entityForm.controls['maxNumberOfPartitionsPerQueue'].enable(); + this.entityForm.get('maxNumberOfQueues').enable(); + this.entityForm.get('maxNumberOfPartitionsPerQueue').enable(); } else { - this.entityForm.controls['maxNumberOfQueues'].disable(); - this.entityForm.controls['maxNumberOfPartitionsPerQueue'].disable(); + this.entityForm.get('maxNumberOfQueues').disable(); + this.entityForm.get('maxNumberOfPartitionsPerQueue').disable(); } return isolatedTbRuleEngine; } diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index dc3c5200d3..311529a42a 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -98,6 +98,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan export interface TenantProfileData { configuration: TenantProfileConfiguration; + queueConfiguration?: any; } export interface TenantProfile extends BaseData { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 910632d072..4c93854125 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -259,7 +259,8 @@ "queues": "Queues", "queue-partitions": "Partitions", "queue-submit-strategy": "Submit strategy", - "queue-processing-strategy": "Processing strategy" + "queue-processing-strategy": "Processing strategy", + "queue-configuration": "Queue configuration" }, "alarm": { "alarm": "Alarm", From 9b19da096f6b832567b2e9aeec9b94da2e882c23 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 21 Apr 2022 09:51:25 +0200 Subject: [PATCH 12/58] removed max queues and max partitions per queue in tenant profile --- .../server/controller/QueueController.java | 14 +-- .../server/dao/queue/QueueService.java | 3 - .../server/common/data/TenantProfile.java | 6 +- .../server/dao/model/ModelConstants.java | 2 - .../dao/model/sql/TenantProfileEntity.java | 10 --- .../server/dao/queue/BaseQueueService.java | 37 -------- .../dao/tenant/TenantProfileServiceImpl.java | 85 +++++++++++++++++++ .../main/resources/sql/schema-entities.sql | 2 - .../dao/service/BaseQueueServiceTest.java | 49 ++++++----- .../service/BaseTenantProfileServiceTest.java | 28 ++++++ ui-ngx/src/app/core/http/queue.service.ts | 10 +-- .../import-export/import-export.service.ts | 4 +- .../tenant-profile-data.component.html | 5 ++ .../profile/tenant-profile.component.html | 32 ------- .../profile/tenant-profile.component.ts | 12 +-- ui-ngx/src/app/shared/models/tenant.model.ts | 2 - .../assets/locale/locale.constant-en_US.json | 8 +- 17 files changed, 159 insertions(+), 150 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index c48fc8036f..dd0e023152 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -55,7 +55,7 @@ public class QueueController extends BaseController { @ApiOperation(value = "Get queue names (getTenantQueuesByServiceType)", notes = "Returns a set of unique queue names based on service type. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/tenant/queues", params = {"serviceType"}, produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + @RequestMapping(value = "/queues", params = {"serviceType"}, produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) @ResponseBody() public Set getTenantQueuesByServiceType(@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES) @RequestParam String serviceType) throws ThingsboardException { @@ -74,7 +74,7 @@ public class QueueController extends BaseController { } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - @RequestMapping(value = "/tenant/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET) + @RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET) @ResponseBody public PageData getTenantQueuesByServiceType(@RequestParam String serviceType, @RequestParam int pageSize, @@ -98,7 +98,7 @@ public class QueueController extends BaseController { } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - @RequestMapping(value = "/tenant/queues/{queueId}", method = RequestMethod.GET) + @RequestMapping(value = "/queues/{queueId}", method = RequestMethod.GET) @ResponseBody public Queue getQueueById(@PathVariable("queueId") String queueIdStr) throws ThingsboardException { checkParameter("queueId", queueIdStr); @@ -111,8 +111,8 @@ public class QueueController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - @RequestMapping(value = "/tenant/queues", params = {"serviceType"}, method = RequestMethod.POST) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") + @RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST) @ResponseBody public Queue saveQueue(@RequestBody Queue queue, @RequestParam String serviceType) throws ThingsboardException { @@ -137,8 +137,8 @@ public class QueueController extends BaseController { } } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - @RequestMapping(value = "/tenant/queues/{queueId}", method = RequestMethod.DELETE) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") + @RequestMapping(value = "/queues/{queueId}", method = RequestMethod.DELETE) @ResponseBody public void deleteQueue(@PathVariable("queueId") String queueIdStr) throws ThingsboardException { checkParameter("queueId", queueIdStr); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java index 3fbb228f3c..bdea0ef09c 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.queue; -import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -42,7 +41,5 @@ public interface QueueService { Queue findQueueByTenantIdAndName(TenantId tenantId, String name); - Queue createDefaultMainQueue(TenantProfile tenantProfile, TenantId tenantId); - void deleteQueuesByTenantId(TenantId tenantId); } \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java index 32b6ba88ba..308500a6bd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java @@ -57,11 +57,7 @@ public class TenantProfile extends SearchTextBased implements H @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") private boolean isolatedTbRuleEngine; - @ApiModelProperty(position = 8, value = "Max amount of queues configurable by isolated tenant.", example = "5") - private Integer maxNumberOfQueues; - @ApiModelProperty(position = 9, value = "Max amount of partitions per queue configurable by isolated tenant.", example = "10") - private Integer maxNumberOfPartitionsPerQueue; - @ApiModelProperty(position = 10, value = "Complex JSON object that contains profile settings: max devices, max assets, rate limits, etc.") + @ApiModelProperty(position = 8, value = "Complex JSON object that contains profile settings: queue configs, max devices, max assets, rate limits, etc.") private transient TenantProfileData profileData; @JsonIgnore private byte[] profileDataBytes; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index c9f89ccc91..d122f712ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -128,8 +128,6 @@ public class ModelConstants { public static final String TENANT_PROFILE_IS_DEFAULT_PROPERTY = "is_default"; public static final String TENANT_PROFILE_ISOLATED_TB_CORE = "isolated_tb_core"; public static final String TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE = "isolated_tb_rule_engine"; - public static final String TENANT_PROFILE_MAX_NUMBER_OF_QUEUES = "max_number_of_queues"; - public static final String TENANT_PROFILE_MAX_NUMBER_OF_PARTITIONS_PER_QUEUE = "max_number_of_partitions_per_queue"; /** * Cassandra customer constants. diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java index 2b62588c76..6f7b094464 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java @@ -59,12 +59,6 @@ public final class TenantProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE) private boolean isolatedTbRuleEngine; - @Column(name = ModelConstants.TENANT_PROFILE_MAX_NUMBER_OF_QUEUES) - private Integer maxNumberOfQueues; - - @Column(name = ModelConstants.TENANT_PROFILE_MAX_NUMBER_OF_PARTITIONS_PER_QUEUE) - private Integer maxNumberOfPartitionsPerQueue; - @Type(type = "jsonb") @Column(name = ModelConstants.TENANT_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode profileData; @@ -83,8 +77,6 @@ public final class TenantProfileEntity extends BaseSqlEntity impl this.isDefault = tenantProfile.isDefault(); this.isolatedTbCore = tenantProfile.isIsolatedTbCore(); this.isolatedTbRuleEngine = tenantProfile.isIsolatedTbRuleEngine(); - this.maxNumberOfPartitionsPerQueue = tenantProfile.getMaxNumberOfPartitionsPerQueue(); - this.maxNumberOfQueues = tenantProfile.getMaxNumberOfQueues(); this.profileData = JacksonUtil.convertValue(tenantProfile.getProfileData(), ObjectNode.class); } @@ -111,8 +103,6 @@ public final class TenantProfileEntity extends BaseSqlEntity impl tenantProfile.setDefault(isDefault); tenantProfile.setIsolatedTbCore(isolatedTbCore); tenantProfile.setIsolatedTbRuleEngine(isolatedTbRuleEngine); - tenantProfile.setMaxNumberOfPartitionsPerQueue(maxNumberOfPartitionsPerQueue); - tenantProfile.setMaxNumberOfQueues(maxNumberOfQueues); tenantProfile.setProfileData(JacksonUtil.convertValue(profileData, TenantProfileData.class)); return tenantProfile; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index 28c0330267..a0ad3c3a4a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -21,14 +21,12 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.queue.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; @@ -202,30 +200,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ tenantQueuesRemover.removeEntities(tenantId, tenantId); } - @Override - @Transactional - public Queue createDefaultMainQueue(TenantProfile tenantProfile, TenantId tenantId) { - Queue mainQueue = new Queue(); - mainQueue.setTenantId(tenantId); - mainQueue.setName("Main"); - mainQueue.setTopic("tb_rule_engine.main"); - mainQueue.setPollInterval(25); - mainQueue.setPartitions(Math.max(tenantProfile.getMaxNumberOfPartitionsPerQueue(), 1)); - mainQueue.setPackProcessingTimeout(60000); - SubmitStrategy mainQueueSubmitStrategy = new SubmitStrategy(); - mainQueueSubmitStrategy.setType(SubmitStrategyType.BURST); - mainQueueSubmitStrategy.setBatchSize(1000); - mainQueue.setSubmitStrategy(mainQueueSubmitStrategy); - ProcessingStrategy mainQueueProcessingStrategy = new ProcessingStrategy(); - mainQueueProcessingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES); - mainQueueProcessingStrategy.setRetries(3); - mainQueueProcessingStrategy.setFailurePercentage(0); - mainQueueProcessingStrategy.setPauseBetweenRetries(3); - mainQueueProcessingStrategy.setMaxPauseBetweenRetries(3); - mainQueue.setProcessingStrategy(mainQueueProcessingStrategy); - return saveQueue(mainQueue); - } - private DataValidator queueValidator = new DataValidator<>() { @@ -261,17 +235,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ if (!tenantProfile.isIsolatedTbRuleEngine()) { throw new DataValidationException("Tenant should be isolated!"); } - - if (queue.getId() == null) { - List existingQueues = findQueuesByTenantId(tenantId); - if (existingQueues.size() >= tenantProfile.getMaxNumberOfQueues()) { - throw new DataValidationException("The limit for creating new queue has been exceeded!"); - } - } - - if (queue.getPartitions() > tenantProfile.getMaxNumberOfPartitionsPerQueue()) { - throw new DataValidationException(String.format("Queue partitions can't be more then %d", tenantProfile.getMaxNumberOfPartitionsPerQueue())); - } } if (StringUtils.isEmpty(queue.getName())) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java index a4f9c65807..2b8611846a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java @@ -29,8 +29,12 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategyType; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; @@ -39,6 +43,10 @@ import org.thingsboard.server.dao.service.Validator; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; import static org.thingsboard.server.common.data.CacheConstants.TENANT_PROFILE_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -228,6 +236,35 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T throw new DataValidationException("Another default tenant profile is present!"); } } + + if (tenantProfile.isIsolatedTbRuleEngine()) { + List queueConfiguration = tenantProfile.getProfileData().getQueueConfiguration(); + if (queueConfiguration == null) { + throw new DataValidationException("Tenant profile data queue configuration should be specified!"); + } + + Optional mainQueueConfig = + queueConfiguration + .stream() + .filter(q -> q.getName().equals("Main")) + .findAny(); + if (mainQueueConfig.isEmpty()) { + throw new DataValidationException("Main queue configuration should be specified!"); + } + + queueConfiguration.forEach(this::validateQueueConfiguration); + + Set queueNames = new HashSet<>(queueConfiguration.size()); + + queueConfiguration.forEach(q -> { + String name = q.getName(); + if (queueNames.contains(name)) { + throw new DataValidationException(String.format("Queue configuration name '%s' already present!", name)); + } else { + queueNames.add(name); + } + }); + } } @Override @@ -241,6 +278,54 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T throw new DataValidationException("Can't update isolatedTbCore property!"); } } + + private void validateQueueConfiguration(TenantProfileQueueConfiguration queue) { + if (StringUtils.isEmpty(queue.getName())) { + throw new DataValidationException("Queue name should be specified!"); + } + if (StringUtils.isBlank(queue.getTopic())) { + throw new DataValidationException("Queue topic should be non empty and without spaces!"); + } + if (queue.getPollInterval() < 1) { + throw new DataValidationException("Queue poll interval should be more then 0!"); + } + if (queue.getPartitions() < 1) { + throw new DataValidationException("Queue partitions should be more then 0!"); + } + if (queue.getPackProcessingTimeout() < 1) { + throw new DataValidationException("Queue pack processing timeout should be more then 0!"); + } + + SubmitStrategy submitStrategy = queue.getSubmitStrategy(); + if (submitStrategy == null) { + throw new DataValidationException("Queue submit strategy can't be null!"); + } + if (submitStrategy.getType() == null) { + throw new DataValidationException("Queue submit strategy type can't be null!"); + } + if (submitStrategy.getType() == SubmitStrategyType.BATCH && submitStrategy.getBatchSize() < 1) { + throw new DataValidationException("Queue submit strategy batch size should be more then 0!"); + } + ProcessingStrategy processingStrategy = queue.getProcessingStrategy(); + if (processingStrategy == null) { + throw new DataValidationException("Queue processing strategy can't be null!"); + } + if (processingStrategy.getType() == null) { + throw new DataValidationException("Queue processing strategy type can't be null!"); + } + if (processingStrategy.getRetries() < 0) { + throw new DataValidationException("Queue processing strategy retries can't be less then 0!"); + } + if (processingStrategy.getFailurePercentage() < 0 || processingStrategy.getFailurePercentage() > 100) { + throw new DataValidationException("Queue processing strategy failure percentage should be in a range from 0 to 100!"); + } + if (processingStrategy.getPauseBetweenRetries() < 0) { + throw new DataValidationException("Queue processing strategy pause between retries can't be less then 0!"); + } + if (processingStrategy.getMaxPauseBetweenRetries() < processingStrategy.getPauseBetweenRetries()) { + throw new DataValidationException("Queue processing strategy MAX pause between retries can't be less then pause between retries!"); + } + } }; private PaginatedRemover tenantProfilesRemover = diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index b85171efee..1f3717429b 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -352,8 +352,6 @@ CREATE TABLE IF NOT EXISTS tenant_profile ( is_default boolean, isolated_tb_core boolean, isolated_tb_rule_engine boolean, - max_number_of_queues int , - max_number_of_partitions_per_queue int, CONSTRAINT tenant_profile_name_unq_key UNIQUE (name) ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java index 8899224bd5..577193ff94 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java @@ -30,10 +30,10 @@ 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.tenant.profile.TenantProfileData; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.tenant.TenantServiceImpl; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -47,18 +47,34 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest { @Before public void before() throws NoSuchFieldException, IllegalAccessException { - Field zkEnabled = TenantServiceImpl.class.getDeclaredField("zkEnabled"); - zkEnabled.setAccessible(true); - zkEnabled.set(tenantService, Boolean.TRUE); - 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); - tenantProfile.setMaxNumberOfQueues(10); - tenantProfile.setMaxNumberOfPartitionsPerQueue(10); + + 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 = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); Assert.assertNotNull(savedTenantProfile); @@ -343,23 +359,6 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest { } } - @Test(expected = DataValidationException.class) - public void testSaveQueueWithExceededLimitPerTenant() { - for (int i = 1; i <= 10; i++) { - //main queue created automatically - Queue queue = new Queue(); - queue.setTenantId(tenantId); - queue.setName("Test" + i); - queue.setTopic("tb_rule_engine.test" + i); - queue.setPollInterval(25); - queue.setPartitions(1); - queue.setPackProcessingTimeout(2000); - queue.setSubmitStrategy(createTestSubmitStrategy()); - queue.setProcessingStrategy(createTestProcessingStrategy()); - queueService.saveQueue(queue); - } - } - @Test public void testUpdateQueue() { Queue queue = new Queue(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java index b655a8439c..ae9459ccae 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java @@ -25,8 +25,13 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.ProcessingStrategyType; +import org.thingsboard.server.common.data.queue.SubmitStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategyType; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; 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 java.util.ArrayList; @@ -47,6 +52,29 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest { @Test public void testSaveTenantProfile() { TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); + + 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); + tenantProfile.getProfileData().setQueueConfiguration(Collections.singletonList(mainQueueConfiguration)); + TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); Assert.assertNotNull(savedTenantProfile); Assert.assertNotNull(savedTenantProfile.getId()); diff --git a/ui-ngx/src/app/core/http/queue.service.ts b/ui-ngx/src/app/core/http/queue.service.ts index bf2183449d..a5967eef97 100644 --- a/ui-ngx/src/app/core/http/queue.service.ts +++ b/ui-ngx/src/app/core/http/queue.service.ts @@ -32,26 +32,26 @@ export class QueueService { ) { } public getTenantQueuesNamesByServiceType(serviceType: ServiceType, config?: RequestConfig): Observable> { - return this.http.get>(`/api/tenant/queues?serviceType=${serviceType}`, + return this.http.get>(`/api/queues?serviceType=${serviceType}`, defaultHttpOptionsFromConfig(config)); } public getQueueById(queueId: string, config?: RequestConfig): Observable { - return this.http.get(`/api/tenant/queues/${queueId}`, defaultHttpOptionsFromConfig(config)); + return this.http.get(`/api/queues/${queueId}`, defaultHttpOptionsFromConfig(config)); } public getTenantQueuesByServiceType(pageLink: PageLink, serviceType: ServiceType, config?: RequestConfig): Observable> { - return this.http.get>(`/api/tenant/queues${pageLink.toQuery()}&serviceType=${serviceType}`, + return this.http.get>(`/api/queues${pageLink.toQuery()}&serviceType=${serviceType}`, defaultHttpOptionsFromConfig(config)); } public saveQueue(queue: QueueInfo, serviceType: ServiceType, config?: RequestConfig): Observable { - return this.http.post(`/api/tenant/queues?serviceType=${serviceType}`, queue, defaultHttpOptionsFromConfig(config)); + return this.http.post(`/api/queues?serviceType=${serviceType}`, queue, defaultHttpOptionsFromConfig(config)); } public deleteQueue(queueId: string) { - return this.http.delete(`/api/tenant/queues/${queueId}`); + return this.http.delete(`/api/queues/${queueId}`); } } diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts index 78507cb121..2bddd229bc 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts @@ -567,9 +567,7 @@ export class ImportExportService { return isDefined(tenantProfile.name) && isDefined(tenantProfile.profileData) && isDefined(tenantProfile.isolatedTbCore) - && isDefined(tenantProfile.isolatedTbRuleEngine) - && isDefined(tenantProfile.maxNumberOfQueues) - && isDefined(tenantProfile.maxNumberOfPartitionsPerQueue); + && isDefined(tenantProfile.isolatedTbRuleEngine); } private sumObject(obj1: any, obj2: any): any { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html index 81ca768911..115a224374 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html @@ -16,6 +16,11 @@ -->
+ + + + + diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index 6377e59a45..e2eb776e5b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -67,38 +67,6 @@
{{ 'tenant.isolated-tb-rule-engine' | translate }}
{{'tenant.isolated-tb-rule-engine-details' | translate}}
-
- - tenant.max-number-of-queues - - - {{ 'tenant.max-number-of-queues-required' | translate }} - - - {{ 'tenant.max-number-of-queues-min-length' | translate }} - - - - tenant.max-number-of-partitions-per-queue - - - {{ 'tenant.max-number-of-partitions-per-queue-required' | translate }} - - - {{ 'tenant.max-number-of-partitions-per-queue-min-length' | translate }} - - -
{ name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], - maxNumberOfQueues: [entity ? entity.maxNumberOfQueues : 1, [Validators.required, Validators.min(1)]], - maxNumberOfPartitionsPerQueue: [entity ? entity.maxNumberOfPartitionsPerQueue : 1, [Validators.required, Validators.min(1)]], profileData: [entity && !this.isAdd ? entity.profileData : { configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT) } as TenantProfileData, []], @@ -81,8 +79,6 @@ export class TenantProfileComponent extends EntityComponent { this.entityForm.patchValue({name: entity.name}); this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore}); this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}); - this.entityForm.patchValue({maxNumberOfQueues: entity.maxNumberOfQueues}); - this.entityForm.patchValue({maxNumberOfPartitionsPerQueue: entity.maxNumberOfPartitionsPerQueue}); this.entityForm.patchValue({profileData: !this.isAdd ? entity.profileData : { configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT) } as TenantProfileData}); @@ -92,11 +88,9 @@ export class TenantProfileComponent extends EntityComponent { showQueueParams(): boolean { let isolatedTbRuleEngine: boolean = this.entityForm.get('isolatedTbRuleEngine').value; if (isolatedTbRuleEngine) { - this.entityForm.get('maxNumberOfQueues').enable(); - this.entityForm.get('maxNumberOfPartitionsPerQueue').enable(); +//enable } else { - this.entityForm.get('maxNumberOfQueues').disable(); - this.entityForm.get('maxNumberOfPartitionsPerQueue').disable(); +//disable } return isolatedTbRuleEngine; } @@ -108,8 +102,6 @@ export class TenantProfileComponent extends EntityComponent { if (!this.isAdd) { this.entityForm.get('isolatedTbCore').disable({emitEvent: false}); this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false}); - this.entityForm.get('maxNumberOfQueues').disable({emitEvent: false}); - this.entityForm.get('maxNumberOfPartitionsPerQueue').disable({emitEvent: false}); } } else { this.entityForm.disable({emitEvent: false}); diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index 311529a42a..cceb1cc7d7 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -107,8 +107,6 @@ export interface TenantProfile extends BaseData { default?: boolean; isolatedTbCore?: boolean; isolatedTbRuleEngine?: boolean; - maxNumberOfQueues?: number; - maxNumberOfPartitionsPerQueue?: number; profileData?: TenantProfileData; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4c93854125..4414e71847 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2759,13 +2759,7 @@ "isolated-tb-core": "Processing in isolated ThingsBoard Core 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", - "max-number-of-queues": "Max number of ThingsBoard Rule Engine queues", - "max-number-of-queues-required": "Max number of queues is required", - "max-number-of-queues-min-length": "Max number of queues can't be less then 1", - "max-number-of-partitions-per-queue": "Max number of partitions per ThingsBoard Rule Engine queue", - "max-number-of-partitions-per-queue-required": "Max number of partitions per queue is required", - "max-number-of-partitions-per-queue-min-length": "Max number of partitions per queue can't be less then 1" + "isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant" }, "tenant-profile": { "tenant-profile": "Tenant profile", From aba3974a77e1fc465bc6c28dc25fe97d5157be31 Mon Sep 17 00:00:00 2001 From: fe-dev Date: Fri, 29 Apr 2022 19:18:11 +0300 Subject: [PATCH 13/58] UI: add queues to tenant profile --- ui-ngx/src/app/modules/common/modules-map.ts | 4 + .../home/components/home-components.module.ts | 10 +- .../profile/device-profile.component.ts | 4 +- .../queue/tenant-profile-queue.component.html | 194 +++++++++++++++++ .../queue/tenant-profile-queue.component.scss | 22 ++ .../queue/tenant-profile-queue.component.ts | 206 ++++++++++++++++++ .../tenant-profile-queues.component.html | 42 ++++ .../tenant-profile-queues.component.scss | 31 +++ .../queue/tenant-profile-queues.component.ts | 178 +++++++++++++++ .../tenant-profile-data.component.html | 5 - .../profile/tenant-profile-data.component.ts | 2 +- .../profile/tenant-profile.component.html | 24 +- .../profile/tenant-profile.component.scss | 10 + .../profile/tenant-profile.component.ts | 78 ++++--- .../pages/admin/queue/queue.component.html | 204 +++++++++-------- .../pages/admin/queue/queue.component.scss | 43 +--- .../home/pages/admin/queue/queue.component.ts | 6 +- ui-ngx/src/app/shared/models/queue.models.ts | 7 +- ui-ngx/src/app/shared/models/tenant.model.ts | 4 +- .../assets/locale/locale.constant-en_US.json | 5 +- 20 files changed, 878 insertions(+), 201 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index b4f4ea1328..bfc8f60604 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -287,6 +287,8 @@ import * as DisplayWidgetTypesPanelComponent from '@home/components/dashboard-pa import * as AlarmDurationPredicateValueComponent from '@home/components/profile/alarm/alarm-duration-predicate-value.component'; import * as DashboardImageDialogComponent from '@home/components/dashboard-page/dashboard-image-dialog.component'; import * as WidgetContainerComponent from '@home/components/widget/widget-container.component'; +import * as TenantProfileQueuesComponent from '@home/components/profile/queue/tenant-profile-queues.component'; +import { TenantProfileQueueComponent } from '@home/components/profile/queue/tenant-profile-queue.component'; import { IModulesMap } from '@modules/common/modules-map.models'; @@ -570,6 +572,8 @@ class ModulesMap implements IModulesMap { '@home/components/profile/alarm/alarm-duration-predicate-value.component': AlarmDurationPredicateValueComponent, '@home/components/dashboard-page/dashboard-image-dialog.component': DashboardImageDialogComponent, '@home/components/widget/widget-container.component': WidgetContainerComponent, + '@home/components/profile/queue/tenant-profile-queues.component': TenantProfileQueuesComponent, + '@home/components/profile/queue/tenant-profile-queue.component': TenantProfileQueueComponent }; init() { diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 0c58328e46..282a494026 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -148,6 +148,8 @@ import { } from '@home/components/tokens'; import { DashboardStateComponent } from '@home/components/dashboard-page/dashboard-state.component'; import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component'; +import { TenantProfileQueuesComponent } from '@home/components/profile/queue/tenant-profile-queues.component'; +import { TenantProfileQueueComponent } from '@home/components/profile/queue/tenant-profile-queue.component'; @NgModule({ declarations: @@ -267,7 +269,9 @@ import { EntityDetailsPageComponent } from '@home/components/entity/entity-detai DashboardStateDialogComponent, DashboardImageDialogComponent, EmbedDashboardDialogComponent, - DisplayWidgetTypesPanelComponent + DisplayWidgetTypesPanelComponent, + TenantProfileQueuesComponent, + TenantProfileQueueComponent ], imports: [ CommonModule, @@ -380,7 +384,9 @@ import { EntityDetailsPageComponent } from '@home/components/entity/entity-detai DashboardStateDialogComponent, DashboardImageDialogComponent, EmbedDashboardDialogComponent, - DisplayWidgetTypesPanelComponent + DisplayWidgetTypesPanelComponent, + TenantProfileQueuesComponent, + TenantProfileQueueComponent ], providers: [ WidgetComponentService, diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index d30f5a8753..0d33079b0b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -42,7 +42,7 @@ import { ServiceType } from '@shared/models/queue.models'; import { EntityId } from '@shared/models/id/entity-id'; import { OtaUpdateType } from '@shared/models/ota-package.models'; import { DashboardId } from '@shared/models/id/dashboard-id'; -import { QueueId } from "@shared/models/id/queue-id"; +import { QueueId } from '@shared/models/id/queue-id'; @Component({ selector: 'tb-device-profile', @@ -198,7 +198,7 @@ export class DeviceProfileComponent extends EntityComponent { }}, {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({defaultQueueId: entity.defaultQueueId ? entity.defaultQueueId.id: null}, {emitEvent: false}); + this.entityForm.patchValue({defaultQueueId: entity.defaultQueueId ? entity.defaultQueueId.id : null}, {emitEvent: false}); this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false}); this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html new file mode 100644 index 0000000000..07bcb5d9e8 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html @@ -0,0 +1,194 @@ + + + +
+ +
+ {{ queueTitle }} +
+
+ + +
+
+ +
+ + + admin.queue-name + + + {{ 'queue.name-required' | translate }} + + + + queue.poll-interval + + + {{ 'queue.poll-interval-required' | translate }} + + + {{ 'queue.poll-interval-min-value' | translate }} + + + + queue.partitions + + + {{ 'queue.partitions-required' | translate }} + + + {{ 'queue.partitions-min-value' | translate }} + + + + +
{{ 'queue.consumer-per-partition' | translate }}
+
{{'queue.consumer-per-partition-hint' | translate}}
+
+ + + queue.processing-timeout + + + {{ 'queue.pack-processing-timeout-required' | translate }} + + + {{ 'queue.pack-processing-timeout-min-value' | translate }} + + + + + + + queue.submit-strategy + + + +
+ + queue.submit-strategy + + + {{ strategy }} + + + + {{ 'queue.submit-strategy-type-required' | translate }} + + + + queue.batch-size + + + {{ 'queue.batch-size-required' | translate }} + + + {{ 'queue.batch-size-min-value' | translate }} + + +
+
+
+ + + + queue.processing-strategy + + + +
+ + queue.processing-strategy + + + {{ strategy }} + + + + {{ 'queue.processing-strategy-type-required' | translate }} + + + + queue.retries + + + {{ 'queue.retries-required' | translate }} + + + {{ 'queue.retries-min-value' | translate }} + + + + queue.failure-percentage + + + {{ 'queue.failure-percentage-required' | translate }} + + + {{ 'queue.failure-percentage-min-value' | translate }} + + + {{ 'queue.failure-percentage-max-value' | translate }} + + + + queue.pause-between-retries + + + {{ 'queue.pause-between-retries-required' | translate }} + + + {{ 'queue.pause-between-retries-min-value' | translate }} + + + + queue.max-pause-between-retries + + + {{ 'queue.max-pause-between-retries-required' | translate }} + + + {{ 'queue.max-pause-between-retries-min-value' | translate }} + + +
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss new file mode 100644 index 0000000000..d20faee49c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss @@ -0,0 +1,22 @@ +/** + * 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. + */ +:host ::ng-deep { + .queue-strategy { + .mat-expansion-panel-body { + padding-bottom: 0 !important; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts new file mode 100644 index 0000000000..7eb0062293 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts @@ -0,0 +1,206 @@ +/// +/// 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. +/// + +import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { + ControlValueAccessor, + FormBuilder, + FormControl, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + Validator, + Validators +} from '@angular/forms'; +import { DeviceProfileAlarm } from '@shared/models/device.models'; +import { MatDialog } from '@angular/material/dialog'; +import { UtilsService } from '@core/services/utils.service'; +import { QueueProcessingStrategyTypes, QueueSubmitStrategyTypes } from '@shared/models/queue.models'; + +@Component({ + selector: 'tb-tenant-profile-queue', + templateUrl: './tenant-profile-queue.component.html', + styleUrls: ['./tenant-profile-queue.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TenantProfileQueueComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => TenantProfileQueueComponent), + multi: true, + } + ] +}) +export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit, Validator { + + @Input() + disabled: boolean; + + @Output() + removeQueue = new EventEmitter(); + + @Input() + expanded = false; + + @Input() + mainQueue = false; + + @Input() + newQueue = false; + + private modelValue: DeviceProfileAlarm; + + queueFormGroup: FormGroup; + + submitStrategies: string[] = []; + processingStrategies: string[] = []; + + hideBatchSize = false; + + private propagateChange = null; + private propagateChangePending = false; + + constructor(private dialog: MatDialog, + private utils: UtilsService, + private fb: FormBuilder) { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + if (this.propagateChangePending) { + this.propagateChangePending = false; + setTimeout(() => { + this.propagateChange(this.modelValue); + }, 0); + } + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.submitStrategies = Object.values(QueueSubmitStrategyTypes); + this.processingStrategies = Object.values(QueueProcessingStrategyTypes); + this.queueFormGroup = this.fb.group( + { + name: ['', [Validators.required]], + pollInterval: [25, [Validators.min(1), Validators.required]], + partitions: [10, [Validators.min(1), Validators.required]], + consumerPerPartition: [false, []], + packProcessingTimeout: [2000, [Validators.min(1), Validators.required]], + submitStrategy: this.fb.group({ + type: [null, [Validators.required]], + batchSize: [0, [Validators.min(1), Validators.required]], + }), + processingStrategy: this.fb.group({ + type: [null, [Validators.required]], + retries: [3, [Validators.min(0), Validators.required]], + failurePercentage: [ 0, [Validators.min(0), Validators.required, Validators.max(100)]], + pauseBetweenRetries: [3, [Validators.min(1), Validators.required]], + maxPauseBetweenRetries: [3, [Validators.min(1), Validators.required]], + }), + topic: [''] + }); + this.queueFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + this.queueFormGroup.get('name').valueChanges.subscribe((value) => this.queueFormGroup.patchValue({topic: `tb_rule_engine.${value}`})); + this.queueFormGroup.get('submitStrategy').get('type').valueChanges.subscribe(() => { + this.submitStrategyTypeChanged(); + }); + if (this.newQueue) { + this.queueFormGroup.get('name').enable({emitEvent: false}); + } else { + this.queueFormGroup.get('name').disable({emitEvent: false}); + } + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.queueFormGroup.disable({emitEvent: false}); + } else { + this.queueFormGroup.enable({emitEvent: false}); + this.queueFormGroup.get('name').disable({emitEvent: false}); + } + } + + writeValue(value: DeviceProfileAlarm): void { + this.propagateChangePending = false; + this.modelValue = value; + if (!this.modelValue.alarmType) { + this.expanded = true; + } + this.queueFormGroup.reset(this.modelValue || undefined, {emitEvent: false}); + if (!this.disabled && !this.queueFormGroup.valid) { + this.updateModel(); + } + } + + public validate(c: FormControl) { + if (c.parent) { + const queueName = c.value.name; + const profileQueues = []; + c.parent.getRawValue().forEach((queue) => { + profileQueues.push(queue.name); + } + ); + if (profileQueues.filter(profileQueue => profileQueue === queueName).length > 1) { + this.queueFormGroup.get('name').setErrors({ + unique: true + }); + } + } + return (this.queueFormGroup.valid) ? null : { + queue: { + valid: false, + }, + }; + } + + get queueTitle(): string { + const queueName = this.queueFormGroup.get('name').value; + return this.utils.customTranslation(queueName, queueName); + } + + private updateModel() { + const value = this.queueFormGroup.value; + this.modelValue = {...this.modelValue, ...value}; + if (this.propagateChange) { + this.propagateChange(this.modelValue); + } else { + this.propagateChangePending = true; + } + } + + submitStrategyTypeChanged() { + const form = this.queueFormGroup.get('submitStrategy') as FormGroup; + const type: QueueSubmitStrategyTypes = form.get('type').value; + const batchSizeField = form.get('batchSize'); + if (type === QueueSubmitStrategyTypes.BATCH) { + batchSizeField.enable(); + batchSizeField.patchValue(1000); + this.hideBatchSize = true; + } else { + batchSizeField.patchValue(null); + batchSizeField.disable(); + this.hideBatchSize = false; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html new file mode 100644 index 0000000000..59b7e063a1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html @@ -0,0 +1,42 @@ + +
+
+ +
+ + +
+
+
+
+ tenant-profile.no-queue +
+
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss new file mode 100644 index 0000000000..9702d807a6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss @@ -0,0 +1,31 @@ +/** + * 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. + */ +@import '../../../../../../scss/constants'; + +:host { + .tb-tenant-profile-queues { + &.mat-padding { + padding: 8px; + @media #{$mat-gt-sm} { + padding: 16px; + } + } + } + + .tb-prompt{ + margin: 30px 0; + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts new file mode 100644 index 0000000000..abcde44419 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts @@ -0,0 +1,178 @@ +/// +/// 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. +/// + +import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + FormArray, + FormBuilder, + FormControl, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + Validator, + Validators +} from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@app/core/core.state'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Subscription } from 'rxjs'; +import { QueueInfo } from '@shared/models/queue.models'; + +@Component({ + selector: 'tb-tenant-profile-queues', + templateUrl: './tenant-profile-queues.component.html', + styleUrls: ['./tenant-profile-queues.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TenantProfileQueuesComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => TenantProfileQueuesComponent), + multi: true, + } + ] +}) +export class TenantProfileQueuesComponent implements ControlValueAccessor, OnInit, Validator { + + tenantProfileQueuesFormGroup: FormGroup; + newQueue = false; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + @Input() + disabled: boolean; + + private valueChangeSubscription: Subscription = null; + + private propagateChange = (v: any) => { }; + + constructor(private store: Store, + private fb: FormBuilder) { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.tenantProfileQueuesFormGroup = this.fb.group({ + queues: this.fb.array([]) + }); + } + + queuesFormArray(): FormArray { + return this.tenantProfileQueuesFormGroup.get('queues') as FormArray; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.tenantProfileQueuesFormGroup.disable({emitEvent: false}); + } else { + this.tenantProfileQueuesFormGroup.enable({emitEvent: false}); + } + } + + writeValue(queues: Array | null): void { + if (this.valueChangeSubscription) { + this.valueChangeSubscription.unsubscribe(); + } + const queuesControls: Array = []; + if (queues) { + queues.forEach((queue) => { + queuesControls.push(this.fb.control(queue, [Validators.required])); + }); + } + this.tenantProfileQueuesFormGroup.setControl('queues', this.fb.array(queuesControls)); + if (this.disabled) { + this.tenantProfileQueuesFormGroup.disable({emitEvent: false}); + } else { + this.tenantProfileQueuesFormGroup.enable({emitEvent: false}); + } + this.valueChangeSubscription = this.tenantProfileQueuesFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + } + + public trackByQueue(index: number, queueControl: AbstractControl): string { + if (queueControl) { + return queueControl.value.id; + } else { + return null; + } + } + + public removeQueue(index: number) { + (this.tenantProfileQueuesFormGroup.get('queues') as FormArray).removeAt(index); + } + + public addQueue() { + const queue = { + consumerPerPartition: false, + name: '', + packProcessingTimeout: 2000, + partitions: 10, + pollInterval: 25, + processingStrategy: { + failurePercentage: 0, + maxPauseBetweenRetries: 3, + pauseBetweenRetries: 3, + retries: 3, + type: '' + }, + submitStrategy: { + batchSize: 0, + type: '' + }, + topic: '' + }; + this.newQueue = true; + const queuesArray = this.tenantProfileQueuesFormGroup.get('queues') as FormArray; + queuesArray.push(this.fb.control(queue, [])); + this.tenantProfileQueuesFormGroup.updateValueAndValidity(); + if (!this.tenantProfileQueuesFormGroup.valid) { + this.updateModel(); + } + } + + public validate(c: FormControl) { + return (this.tenantProfileQueuesFormGroup.valid) ? null : { + queues: { + valid: false, + }, + }; + } + + private updateModel() { + const queues: Array = this.tenantProfileQueuesFormGroup.get('queues').value; + this.propagateChange(queues); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html index 115a224374..81ca768911 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html @@ -16,11 +16,6 @@ --> - - - - - diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts index 421915ed83..af59fbdf17 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.ts @@ -79,7 +79,7 @@ export class TenantProfileDataComponent implements ControlValueAccessor, OnInit } writeValue(value: TenantProfileData | null): void { - this.tenantProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); + this.tenantProfileDataFormGroup.patchValue({configuration: value}, {emitEvent: false}); } private updateModel() { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index e2eb776e5b..4b511037e7 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -68,10 +68,26 @@
{{'tenant.isolated-tb-rule-engine-details' | translate}}
- - + + + + +
{{'tenant-profile.queues-with-count' | translate: + {count: entityForm.get('profileData').get('queueConfiguration').value ? + entityForm.get('profileData').get('queueConfiguration').value.length : 0} }}
+
+
+ + + +
+ + +
tenant-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss index 21c4f53c08..e6e5d3b9cf 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss @@ -25,4 +25,14 @@ white-space: normal; } } + .fields-group { + padding: 0 16px 8px; + margin-bottom: 10px; + border: 1px groove rgba(0, 0, 0, .25); + border-radius: 4px; + legend { + color: rgba(0, 0, 0, .7); + width: fit-content; + } + } } diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts index 9fd3bb47dd..285cecc5e6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts @@ -18,12 +18,7 @@ import { ChangeDetectorRef, Component, Inject, Input, Optional } from '@angular/ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { - createTenantProfileConfiguration, - TenantProfile, - TenantProfileData, - TenantProfileType -} from '@shared/models/tenant.model'; +import { createTenantProfileConfiguration, TenantProfile, TenantProfileType } from '@shared/models/tenant.model'; import { ActionNotificationShow } from '@app/core/notification/notification.actions'; import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; @@ -48,11 +43,6 @@ export class TenantProfileComponent extends EntityComponent { super(store, fb, entityValue, entitiesTableConfigValue, cd); } - ngOnInit() { - this.showQueueParams(); - this.entityForm.get('isolatedTbRuleEngine').valueChanges.subscribe(() => this.showQueueParams()); - } - hideDelete() { if (this.entitiesTableConfig) { return !this.entitiesTableConfig.deleteEnabled(this.entity); @@ -62,37 +52,61 @@ export class TenantProfileComponent extends EntityComponent { } buildForm(entity: TenantProfile): FormGroup { - return this.fb.group( + const mainQueue = [ + { + consumerPerPartition: true, + name: 'Main', + packProcessingTimeout: 2000, + partitions: 10, + pollInterval: 25, + processingStrategy: { + failurePercentage: 0, + maxPauseBetweenRetries: 3, + pauseBetweenRetries: 3, + retries: 3, + type: 'SKIP_ALL_FAILURES' + }, + submitStrategy: { + batchSize: 1000, + type: 'BURST' + }, + topic: 'tb_rule_engine.main' + } + ]; + const formGroup = this.fb.group( { name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], - profileData: [entity && !this.isAdd ? entity.profileData : { - configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT) - } as TenantProfileData, []], + profileData: this.fb.group({ + configuration: [entity && !this.isAdd ? entity?.profileData.configuration + : createTenantProfileConfiguration(TenantProfileType.DEFAULT), []], + queueConfiguration: [null, []] + }), description: [entity ? entity.description : '', []], } ); + formGroup.get('isolatedTbRuleEngine').valueChanges.subscribe((value) => { + if (value) { + formGroup.get('profileData').patchValue({ + queueConfiguration: mainQueue + }, {emitEvent: false}); + } else { + formGroup.get('profileData').patchValue({ + queueConfiguration: null + }, {emitEvent: false}); + } + }); + return formGroup; } updateForm(entity: TenantProfile) { - this.entityForm.patchValue({name: entity.name}); - this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore}); - this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}); - this.entityForm.patchValue({profileData: !this.isAdd ? entity.profileData : { - configuration: createTenantProfileConfiguration(TenantProfileType.DEFAULT) - } as TenantProfileData}); - this.entityForm.patchValue({description: entity.description}); - } - - showQueueParams(): boolean { - let isolatedTbRuleEngine: boolean = this.entityForm.get('isolatedTbRuleEngine').value; - if (isolatedTbRuleEngine) { -//enable - } else { -//disable - } - return isolatedTbRuleEngine; + 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.get('profileData').patchValue({configuration: entity.profileData?.configuration}, {emitEvent: false}); + this.entityForm.get('profileData').patchValue({queueConfiguration: entity.profileData?.queueConfiguration}, {emitEvent: false}); + this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); } updateFormState() { diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html index ae8f08e348..9d7b9ead45 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html @@ -20,12 +20,12 @@ [disabled]="(isLoading$ | async)" (click)="onEntityAction($event, 'delete')" [fxShow]="!hideDelete() && !isEdit"> - {{'queue.delete' | translate }} + {{ 'queue.delete' | translate }}
- +
admin.queue-name @@ -57,10 +57,6 @@ - - - -
{{ 'queue.consumer-per-partition' | translate }}
{{'queue.consumer-per-partition-hint' | translate}}
@@ -77,115 +73,113 @@ {{ 'queue.pack-processing-timeout-min-value' | translate }} - -
- + - - queue.submit-strategy - {{panel1.expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }} + + queue.submit-strategy -
- - queue.submit-strategy - - - {{ strategy }} - - - - {{ 'queue.submit-strategy-type-required' | translate }} - - - - queue.batch-size - - - {{ 'queue.batch-size-required' | translate }} - - - {{ 'queue.batch-size-min-value' | translate }} - - -
+ +
+ + queue.submit-strategy + + + {{ strategy }} + + + + {{ 'queue.submit-strategy-type-required' | translate }} + + + + queue.batch-size + + + {{ 'queue.batch-size-required' | translate }} + + + {{ 'queue.batch-size-min-value' | translate }} + + +
+
- + - - queue.processing-strategy - {{panel2.expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }} + + queue.processing-strategy - -
- - queue.processing-strategy - - - {{ strategy }} - - - - {{ 'queue.processing-strategy-type-required' | translate }} - - - - queue.retries - - - {{ 'queue.retries-required' | translate }} - - - {{ 'queue.retries-min-value' | translate }} - - - - queue.failure-percentage - - - {{ 'queue.failure-percentage-required' | translate }} - - - {{ 'queue.failure-percentage-min-value' | translate }} - - - {{ 'queue.failure-percentage-max-value' | translate }} - - - - queue.pause-between-retries - - - {{ 'queue.pause-between-retries-required' | translate }} - - - {{ 'queue.pause-between-retries-min-value' | translate }} - - - - queue.max-pause-between-retries - - - {{ 'queue.max-pause-between-retries-required' | translate }} - - - {{ 'queue.max-pause-between-retries-min-value' | translate }} - - -
+ +
+ + queue.processing-strategy + + + {{ strategy }} + + + + {{ 'queue.processing-strategy-type-required' | translate }} + + + + queue.retries + + + {{ 'queue.retries-required' | translate }} + + + {{ 'queue.retries-min-value' | translate }} + + + + queue.failure-percentage + + + {{ 'queue.failure-percentage-required' | translate }} + + + {{ 'queue.failure-percentage-min-value' | translate }} + + + {{ 'queue.failure-percentage-max-value' | translate }} + + + + queue.pause-between-retries + + + {{ 'queue.pause-between-retries-required' | translate }} + + + {{ 'queue.pause-between-retries-min-value' | translate }} + + + + queue.max-pause-between-retries + + + {{ 'queue.max-pause-between-retries-required' | translate }} + + + {{ 'queue.max-pause-between-retries-min-value' | translate }} + + +
+
-
diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss index 852e391b28..c87504819e 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss @@ -14,46 +14,9 @@ * limitations under the License. */ :host ::ng-deep { - - .mat-expansion-panel:not([class*='mat-elevation-z']) { - box-shadow: none; - } - - .mat-accordion-container { - margin-bottom: 16px; - } - - .mat-expansion-panel { - - &:hover { - box-shadow: 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 5px 5px -3px rgba(0, 0, 0, 0.2); - } - - &-header { - height: 56px; - border: 1px solid #f2f2f2; - - &-title { - align-items: center; - justify-content: space-between; - margin-right: 0; - } - } - - &.mat-expanded { - border: none; - box-shadow: 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 5px 5px -3px rgba(0, 0, 0, 0.2); - - .mat-expansion-panel { - - &-content { - margin-top: 20px; - } - - &-body { - padding-bottom: 10px; - } - } + .queue-form { + .mat-expansion-panel-body { + padding-bottom: 0 !important; } } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts index f9a60773df..f436264793 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts @@ -23,8 +23,6 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; -import set = Reflect.set; -import { distinctUntilChanged } from 'rxjs/operators'; @Component({ selector: 'tb-queue', @@ -39,7 +37,7 @@ export class QueueComponent extends EntityComponent { processingStrategies: string[] = []; QueueSubmitStrategyTypes = QueueSubmitStrategyTypes; - hideBatchSize: boolean = false; + hideBatchSize = false; constructor(protected store: Store, protected translate: TranslateService, @@ -140,7 +138,7 @@ export class QueueComponent extends EntityComponent { } submitStrategyTypeChanged() { - const form = this.entityForm.get("submitStrategy") as FormGroup; + const form = this.entityForm.get('submitStrategy') as FormGroup; const type: QueueSubmitStrategyTypes = form.get('type').value; const batchSizeField = form.get('batchSize'); if (type === QueueSubmitStrategyTypes.BATCH) { diff --git a/ui-ngx/src/app/shared/models/queue.models.ts b/ui-ngx/src/app/shared/models/queue.models.ts index 508cf2aee1..3224d7dc23 100644 --- a/ui-ngx/src/app/shared/models/queue.models.ts +++ b/ui-ngx/src/app/shared/models/queue.models.ts @@ -16,7 +16,7 @@ import { BaseData, HasId } from '@shared/models/base-data'; import { TenantId } from '@shared/models/id/tenant-id'; -import {QueueId} from "@shared/models/id/queue-id"; +import {QueueId} from '@shared/models/id/queue-id'; export enum ServiceType { TB_CORE = 'TB_CORE', @@ -43,9 +43,10 @@ export enum QueueProcessingStrategyTypes { } export interface QueueInfo extends BaseData { + name: string; packProcessingTimeout: number; partitions: number; - consumerPerPartition: boolean, + consumerPerPartition: boolean; pollInterval: number; processingStrategy: { type: QueueProcessingStrategyTypes, @@ -58,6 +59,6 @@ export interface QueueInfo extends BaseData { type: QueueSubmitStrategyTypes, batchSize: number, }; - tenantId: TenantId; + tenantId?: TenantId; topic: string; } diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index cceb1cc7d7..14c0d232df 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -18,7 +18,7 @@ import { ContactBased } from '@shared/models/contact-based.model'; import { TenantId } from './id/tenant-id'; import { TenantProfileId } from '@shared/models/id/tenant-profile-id'; import { BaseData } from '@shared/models/base-data'; -import {Validators} from "@angular/forms"; +import { QueueInfo } from '@shared/models/queue.models'; export enum TenantProfileType { DEFAULT = 'DEFAULT' @@ -98,7 +98,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan export interface TenantProfileData { configuration: TenantProfileConfiguration; - queueConfiguration?: any; + queueConfiguration?: QueueInfo; } export interface TenantProfile extends BaseData { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4414e71847..880778d6c4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2862,7 +2862,10 @@ "max-sms-range": "Maximum number of SMS sent can't be negative", "max-created-alarms": "Maximum number of alarms created (0 - unlimited)", "max-created-alarms-required": "Maximum number of alarms created is required.", - "max-created-alarms-range": "Maximum number of alarms created can't be negative" + "max-created-alarms-range": "Maximum number of alarms created can't be negative", + "no-queue": "No Queue configured", + "add-queue": "Add Queue", + "queues-with-count": "Queues ({{count}})" }, "timeinterval": { "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", From f74f3a92933cdfc7497d5b2d8f6f44aee9df8bd0 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 2 May 2022 08:23:16 +0200 Subject: [PATCH 14/58] created TbQueueService and improvements --- .../server/controller/TenantController.java | 13 +- .../entity/queue/DefaultTbQueueService.java | 144 ++++++++++++++++++ .../service/entity/queue/TbQueueService.java | 29 ++++ .../entity/tenant/DefaultTbTenantService.java | 135 ++++++++++++++++ .../entity/tenant/TbTenantService.java | 23 +++ .../DefaultSystemDataLoaderService.java | 29 +++- .../DefaultTbRuleEngineConsumerService.java | 2 +- ...ice.java => TbQueueServiceDeprecated.java} | 2 +- .../server/dao/queue/QueueService.java | 4 +- .../server/dao/tenant/TenantService.java | 8 +- ...a => DefaultTbQueueServiceDeprecated.java} | 3 +- .../server/dao/queue/BaseQueueService.java | 108 +------------ .../server/dao/tenant/TenantServiceImpl.java | 85 +---------- 13 files changed, 383 insertions(+), 202 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entity/tenant/TbTenantService.java rename common/cluster-api/src/main/java/org/thingsboard/server/queue/{TbQueueService.java => TbQueueServiceDeprecated.java} (95%) rename common/queue/src/main/java/org/thingsboard/server/queue/{DefaultTbQueueService.java => DefaultTbQueueServiceDeprecated.java} (94%) diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index 496cd60e81..e7fd8e24dc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -18,8 +18,8 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entity.tenant.TbTenantService; import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -63,14 +64,14 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI @TbCoreComponent @RequestMapping("/api") @Slf4j +@RequiredArgsConstructor public class TenantController extends BaseController { private static final String TENANT_INFO_DESCRIPTION = "The Tenant Info object extends regular Tenant object and includes Tenant Profile name. "; - @Autowired - private InstallScripts installScripts; - @Autowired - private TenantService tenantService; + private final InstallScripts installScripts; + private final TenantService tenantService; + private final TbTenantService tbTenantService; @ApiOperation(value = "Get Tenant (getTenantById)", notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @@ -129,7 +130,7 @@ public class TenantController extends BaseController { checkEntity(tenant.getId(), tenant, Resource.TENANT); - tenant = checkNotNull(tenantService.saveTenant(tenant)); + tenant = checkNotNull(tbTenantService.saveTenant(tenant)); if (newTenant) { installScripts.createDefaultRuleChains(tenant.getId()); installScripts.createDefaultEdgeRuleChains(tenant.getId()); diff --git a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java new file mode 100644 index 0000000000..006c9025ba --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java @@ -0,0 +1,144 @@ +/** + * 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.entity.queue; + +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.dao.queue.QueueService; +import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.TbQueueClusterService; +import org.thingsboard.server.queue.util.TbCoreComponent; + +@Slf4j +@Service +@TbCoreComponent +@AllArgsConstructor +public class DefaultTbQueueService implements TbQueueService { + private final QueueService queueService; + private final TbQueueClusterService queueClusterService; + private final TbQueueAdmin tbQueueAdmin; + + @Override + public Queue saveQueue(Queue queue) { + boolean create = queue.getId() == null; + Queue oldQueue; + + if (create) { + oldQueue = null; + } else { + oldQueue = queueService.findQueueById(queue.getTenantId(), queue.getId()); + } + + //TODO: add checkNotNull + Queue savedQueue = queueService.saveQueue(queue); + + if (create) { + onQueueCreated(savedQueue); + } else { + onQueueUpdated(savedQueue, oldQueue); + } + + return savedQueue; + } + + @Override + public void deleteQueue(TenantId tenantId, QueueId queueId) { + Queue queue = queueService.findQueueById(tenantId, queueId); + queueService.deleteQueue(tenantId, queueId); + onQueueDeleted(tenantId, queue); + } + + @Override + public void deleteQueueByQueueName(TenantId tenantId, String queueName) { + Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, queueName); + queueService.deleteQueue(tenantId, queue.getId()); + onQueueDeleted(tenantId, queue); + } + + private void onQueueCreated(Queue queue) { + if (tbQueueAdmin != null) { + for (int i = 0; i < queue.getPartitions(); i++) { + tbQueueAdmin.createTopicIfNotExists( + new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + } + } + + if (queueClusterService != null) { + queueClusterService.onQueueChange(queue); + } + } + + private void onQueueUpdated(Queue queue, Queue oldQueue) { + int oldPartitions = oldQueue.getPartitions(); + int currentPartitions = queue.getPartitions(); + + if (currentPartitions != oldPartitions && tbQueueAdmin != null) { + if (currentPartitions > oldPartitions) { + log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); + for (int i = oldPartitions; i < currentPartitions; i++) { + tbQueueAdmin.createTopicIfNotExists( + new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + } + if (queueClusterService != null) { + queueClusterService.onQueueChange(queue); + } + } else { + log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); + if (queueClusterService != null) { + queueClusterService.onQueueChange(queue); + } + await(); + for (int i = currentPartitions; i < oldPartitions; i++) { + tbQueueAdmin.deleteTopic( + new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + } + } + } else if (!oldQueue.equals(queue) && queueClusterService != null) { + queueClusterService.onQueueChange(queue); + } + } + + private void onQueueDeleted(TenantId tenantId, Queue queue) { + if (queueClusterService != null) { + queueClusterService.onQueueDelete(queue); + await(); + } +// queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); + if (tbQueueAdmin != null) { + for (int i = 0; i < queue.getPartitions(); i++) { + String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); + log.debug("Deleting queue [{}]", fullTopicName); + try { + tbQueueAdmin.deleteTopic(fullTopicName); + } catch (Exception e) { + log.error("Failed to delete queue [{}]", fullTopicName); + } + } + } + } + + @SneakyThrows + private void await() { + Thread.sleep(3000); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java new file mode 100644 index 0000000000..1b37486ba4 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java @@ -0,0 +1,29 @@ +/** + * 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.entity.queue; + +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.Queue; + +public interface TbQueueService { + + Queue saveQueue(Queue queue); + + void deleteQueue(TenantId tenantId, QueueId queueId); + + void deleteQueueByQueueName(TenantId tenantId, String queueName); +} diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java new file mode 100644 index 0000000000..015c88813b --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java @@ -0,0 +1,135 @@ +/** + * 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.entity.tenant; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; +import org.thingsboard.server.dao.queue.QueueService; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TenantProfileService; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entity.queue.TbQueueService; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service +@TbCoreComponent +@AllArgsConstructor +public class DefaultTbTenantService implements TbTenantService { + + private final TenantService tenantService; + private final TbQueueService tbQueueService; + private final QueueService queueService; + private final TenantProfileService tenantProfileService; + private final TbTenantProfileCache tenantProfileCache; + + @Override + public Tenant saveTenant(Tenant tenant) { + boolean updated = tenant.getId() != null; + Tenant oldTenant = updated ? tenantService.findTenantById(tenant.getId()) : null; + List queues; + if (updated) { + + } + + Tenant savedTenant = tenantService.saveTenant(tenant); + tenantProfileCache.evict(tenant.getId()); + updateQueuesForTenant(oldTenant, savedTenant); + return savedTenant; + } + + public void updateQueuesForTenant(Tenant oldTenant, Tenant newTenant) { + TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; + TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, newTenant.getTenantProfileId()); + + TenantId tenantId = newTenant.getId(); + + boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); + boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); + + if (!oldIsolated && !newIsolated) { + return; + } + + if (newTenantProfile.equals(oldTenantProfile)) { + return; + } + + Map oldQueues; + Map newQueues; + + if (oldIsolated) { + oldQueues = oldTenantProfile.getProfileData().getQueueConfiguration().stream() + .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); + } else { + oldQueues = Collections.emptyMap(); + } + + if (newIsolated) { + newQueues = newTenantProfile.getProfileData().getQueueConfiguration().stream() + .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); + } else { + newQueues = Collections.emptyMap(); + } + + List toRemove = new ArrayList<>(); + List toCreate = new ArrayList<>(); + List toUpdate = new ArrayList<>(); + + for (String oldQueue : oldQueues.keySet()) { + if (!newQueues.containsKey(oldQueue)) { + toRemove.add(oldQueue); + } + } + + for (String newQueue : newQueues.keySet()) { + if (oldQueues.containsKey(newQueue)) { + toUpdate.add(newQueue); + } else { + toCreate.add(newQueue); + } + } + + toRemove.forEach(q -> tbQueueService.deleteQueueByQueueName(tenantId, q)); + + toCreate.forEach(key -> tbQueueService.saveQueue(new Queue(tenantId, newQueues.get(key)))); + + toUpdate.forEach(key -> { + Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); + Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, key); + queueToUpdate.setId(foundQueue.getId()); + queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); + + if (queueToUpdate.equals(foundQueue)) { + //Queue not changed + } else { + tbQueueService.saveQueue(queueToUpdate); + } + }); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant/TbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant/TbTenantService.java new file mode 100644 index 0000000000..56b3e5e7ba --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant/TbTenantService.java @@ -0,0 +1,23 @@ +/** + * 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.entity.tenant; + +import org.thingsboard.server.common.data.Tenant; + +public interface TbTenantService { + + Tenant saveTenant(Tenant tenant); +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 37982f4a6d..8b2b99b840 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -79,6 +79,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerService; @@ -208,13 +209,37 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { log.warn(e.getMessage()); } + TenantProfileData isolatedRuleEngineTenantProfileData = new TenantProfileData(); + isolatedRuleEngineTenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration()); + + 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); + + isolatedRuleEngineTenantProfileData.setQueueConfiguration(Collections.singletonList(mainQueueConfiguration)); + TenantProfile isolatedTbRuleEngineProfile = new TenantProfile(); isolatedTbRuleEngineProfile.setDefault(false); isolatedTbRuleEngineProfile.setName("Isolated TB Rule Engine"); isolatedTbRuleEngineProfile.setDescription("Isolated TB Rule Engine tenant profile"); isolatedTbRuleEngineProfile.setIsolatedTbCore(false); isolatedTbRuleEngineProfile.setIsolatedTbRuleEngine(true); - isolatedTbRuleEngineProfile.setProfileData(tenantProfileData); + isolatedTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData); try { tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbRuleEngineProfile); @@ -228,7 +253,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { isolatedTbCoreAndTbRuleEngineProfile.setDescription("Isolated TB Core and TB Rule Engine tenant profile"); isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbCore(true); isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbRuleEngine(true); - isolatedTbCoreAndTbRuleEngineProfile.setProfileData(tenantProfileData); + isolatedTbCoreAndTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData); try { tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreAndTbRuleEngineProfile); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 3f8173b9ac..8e3d07316d 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -407,7 +407,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } - private void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { + private synchronized void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { String queueName = queueUpdateMsg.getQueueName(); TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())); diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueService.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java similarity index 95% rename from common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueService.java rename to common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java index bc7964df7e..2328893abe 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java @@ -19,7 +19,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import java.util.Set; -public interface TbQueueService { +public interface TbQueueServiceDeprecated { Set getQueuesByServiceType(ServiceType serviceType); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java index bdea0ef09c..acc3190da9 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java @@ -29,8 +29,6 @@ public interface QueueService { void deleteQueue(TenantId tenantId, QueueId queueId); - void deleteQueueByQueueName(TenantId tenantId, String queueName); - List findQueuesByTenantId(TenantId tenantId); PageData findQueuesByTenantId(TenantId tenantId, PageLink pageLink); @@ -41,5 +39,7 @@ public interface QueueService { Queue findQueueByTenantIdAndName(TenantId tenantId, String name); + Queue findQueueByTenantIdAndNameInternal(TenantId tenantId, String queueName); + void deleteQueuesByTenantId(TenantId tenantId); } \ No newline at end of file diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index 3471d383f2..b4bf769944 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -29,14 +29,14 @@ public interface TenantService { TenantInfo findTenantInfoById(TenantId tenantId); ListenableFuture findTenantByIdAsync(TenantId callerId, TenantId tenantId); - + Tenant saveTenant(Tenant tenant); - + void deleteTenant(TenantId tenantId); - + PageData findTenants(PageLink pageLink); PageData findTenantInfos(PageLink pageLink); - + void deleteTenants(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java similarity index 94% rename from common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java rename to common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java index e372fb600c..8f4175dad1 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java @@ -16,7 +16,6 @@ package org.thingsboard.server.queue; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -31,7 +30,7 @@ import java.util.stream.Collectors; //@Service @RequiredArgsConstructor -public class DefaultTbQueueService implements TbQueueService { +public class DefaultTbQueueServiceDeprecated implements TbQueueServiceDeprecated { private final TbQueueRuleEngineSettings ruleEngineSettings; private Set ruleEngineQueues; diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index a0ad3c3a4a..c95635a439 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.queue; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -30,15 +29,12 @@ import org.thingsboard.server.common.data.queue.ProcessingStrategy; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.queue.SubmitStrategy; import org.thingsboard.server.common.data.queue.SubmitStrategyType; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.queue.TbQueueAdmin; -import org.thingsboard.server.queue.TbQueueClusterService; import java.util.List; @@ -53,12 +49,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ @Autowired private TbTenantProfileCache tenantProfileCache; - @Autowired(required = false) - private TbQueueAdmin tbQueueAdmin; - - @Autowired(required = false) - private TbQueueClusterService queueClusterService; - // @Autowired // private QueueStatsService queueStatsService; @@ -66,101 +56,13 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ public Queue saveQueue(Queue queue) { log.trace("Executing createOrUpdateQueue [{}]", queue); queueValidator.validate(queue, Queue::getTenantId); - Queue savedQueue; - if (queue.getId() == null) { - savedQueue = createQueue(queue); - } else { - savedQueue = updateQueue(queue); - } - - return savedQueue; - } - - private Queue createQueue(Queue queue) { - Queue createdQueue = queueDao.save(queue.getTenantId(), queue); - if (tbQueueAdmin != null) { - for (int i = 0; i < queue.getPartitions(); i++) { - tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); - } - } - - if (queueClusterService != null) { - queueClusterService.onQueueChange(createdQueue); - } - - return createdQueue; - } - - private Queue updateQueue(Queue queue) { - Queue oldQueue = queueDao.findById(queue.getTenantId(), queue.getUuidId()); - Queue updatedQueue = queueDao.save(queue.getTenantId(), queue); - - int oldPartitions = oldQueue.getPartitions(); - int currentPartitions = queue.getPartitions(); - - if (currentPartitions != oldPartitions && tbQueueAdmin != null) { - if (currentPartitions > oldPartitions) { - log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); - for (int i = oldPartitions; i < currentPartitions; i++) { - tbQueueAdmin.createTopicIfNotExists(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); - } - if (queueClusterService != null) { - queueClusterService.onQueueChange(updatedQueue); - } - } else { - log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); - if (queueClusterService != null) { - queueClusterService.onQueueChange(updatedQueue); - } - await(); - for (int i = currentPartitions; i < oldPartitions; i++) { - tbQueueAdmin.deleteTopic(new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); - } - } - } else if (!oldQueue.equals(queue) && queueClusterService != null) { - queueClusterService.onQueueChange(updatedQueue); - } - - return updatedQueue; + return queueDao.save(queue.getTenantId(), queue); } @Override public void deleteQueue(TenantId tenantId, QueueId queueId) { log.trace("Executing deleteQueue, queueId: [{}]", queueId); - Queue queue = findQueueById(tenantId, queueId); - doDelete(tenantId, queue); - } - - @Override - public void deleteQueueByQueueName(TenantId tenantId, String queueName) { - log.trace("Executing deleteQueueByQueueName, name: [{}]", queueName); - Queue queue = findQueueByTenantIdAndName(tenantId, queueName); - doDelete(tenantId, queue); - } - - private void doDelete(TenantId tenantId, Queue queue) { - if (queueClusterService != null) { - queueClusterService.onQueueDelete(queue); - await(); - } -// queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); - boolean result = queueDao.removeById(tenantId, queue.getUuidId()); - if (result && tbQueueAdmin != null) { - for (int i = 0; i < queue.getPartitions(); i++) { - String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); - log.debug("Deleting queue [{}]", fullTopicName); - try { - tbQueueAdmin.deleteTopic(fullTopicName); - } catch (Exception e) { - log.error("Failed to delete queue [{}]", fullTopicName); - } - } - } - } - - @SneakyThrows - private void await() { - Thread.sleep(3000); + queueDao.removeById(tenantId, queueId.getId()); } @Override @@ -194,6 +96,12 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ return queueDao.findQueueByTenantIdAndName(getSystemOrIsolatedTenantId(tenantId), queueName); } + @Override + public Queue findQueueByTenantIdAndNameInternal(TenantId tenantId, String queueName) { + log.trace("Executing findQueueByTenantIdAndNameInternal, tenantId: [{}] queueName: [{}]", tenantId, queueName); + return queueDao.findQueueByTenantIdAndName(tenantId, queueName); + } + @Override public void deleteQueuesByTenantId(TenantId tenantId) { Validator.validateId(tenantId, "Incorrect tenant id for delete queues request."); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 4b935ca700..dcacaba478 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; @@ -27,8 +28,6 @@ import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; @@ -49,12 +48,6 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.widget.WidgetsBundleService; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.thingsboard.server.dao.service.Validator.validateId; @Service @@ -145,90 +138,14 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe tenant.setTenantProfileId(tenantProfile.getId()); } tenantValidator.validate(tenant, Tenant::getId); - - Tenant oldTenant = tenant.getId() != null ? tenantDao.findById(tenant.getId(), tenant.getUuidId()) : null; - Tenant savedTenant = tenantDao.save(tenant.getId(), tenant); if (tenant.getId() == null) { deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); } - - updateQueuesForTenant(oldTenant, savedTenant); - return savedTenant; } - private void updateQueuesForTenant(Tenant oldTenant, Tenant newTenant) { - TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; - TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, newTenant.getTenantProfileId()); - - TenantId tenantId = newTenant.getId(); - - boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); - boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); - - if (!oldIsolated && !newIsolated) { - return; - } - - if (newTenantProfile.equals(oldTenantProfile)) { - return; - } - - Map oldQueues; - Map newQueues; - - if (oldIsolated) { - oldQueues = oldTenantProfile.getProfileData().getQueueConfiguration().stream() - .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); - } else { - oldQueues = Collections.emptyMap(); - } - - if (newIsolated) { - newQueues = newTenantProfile.getProfileData().getQueueConfiguration().stream() - .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); - } else { - newQueues = Collections.emptyMap(); - } - - List toRemove = new ArrayList<>(); - List toCreate = new ArrayList<>(); - List toUpdate = new ArrayList<>(); - - for (String oldQueue : oldQueues.keySet()) { - if (!newQueues.containsKey(oldQueue)) { - toRemove.add(oldQueue); - } - } - - for (String newQueue : newQueues.keySet()) { - if (oldQueues.containsKey(newQueue)) { - toUpdate.add(newQueue); - } else { - toCreate.add(newQueue); - } - } - - toRemove.forEach(q -> queueService.deleteQueueByQueueName(tenantId, q)); - - toCreate.forEach(key -> queueService.saveQueue(new Queue(tenantId, newQueues.get(key)))); - - toUpdate.forEach(key -> { - Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); - Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, key); - queueToUpdate.setId(foundQueue.getId()); - queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); - - if (queueToUpdate.equals(foundQueue)) { - //Queue not changed - } else { - queueService.saveQueue(queueToUpdate); - } - }); - } - @Override public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); From f4353e2db53ddbb00619436894104286b64245e6 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 2 May 2022 10:04:20 +0200 Subject: [PATCH 15/58] added TbTenantProfileService --- .../server/controller/QueueController.java | 7 +- .../controller/TenantProfileController.java | 11 ++- .../entity/queue/DefaultTbQueueService.java | 77 +++++++++++++++++ .../service/entity/queue/TbQueueService.java | 5 ++ .../entity/tenant/DefaultTbTenantService.java | 86 +------------------ .../DefaultTbTenantProfileService.java | 50 +++++++++++ .../TbTenantProfileService.java | 23 +++++ .../server/dao/tenant/TenantService.java | 5 ++ .../server/dao/sql/tenant/JpaTenantDao.java | 9 ++ .../dao/sql/tenant/TenantRepository.java | 4 + .../server/dao/tenant/TenantDao.java | 3 + .../server/dao/tenant/TenantServiceImpl.java | 10 ++- 12 files changed, 203 insertions(+), 87 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/DefaultTbTenantProfileService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/TbTenantProfileService.java diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index dd0e023152..2d07ea8caa 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entity.queue.TbQueueService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -52,6 +53,8 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHO @RequiredArgsConstructor public class QueueController extends BaseController { + private final TbQueueService tbQueueService; + @ApiOperation(value = "Get queue names (getTenantQueuesByServiceType)", notes = "Returns a set of unique queue names based on service type. " + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -126,7 +129,7 @@ public class QueueController extends BaseController { switch (type) { case TB_RULE_ENGINE: queue.setTenantId(getTenantId()); - Queue savedQueue = queueService.saveQueue(queue); + Queue savedQueue = tbQueueService.saveQueue(queue); checkNotNull(savedQueue); return savedQueue; default: @@ -145,7 +148,7 @@ public class QueueController extends BaseController { try { QueueId queueId = new QueueId(toUUID(queueIdStr)); checkQueueId(queueId, Operation.DELETE); - queueService.deleteQueue(getTenantId(), queueId); + tbQueueService.deleteQueue(getTenantId(), queueId); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 2512a46c1d..f8e821e489 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -37,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entity.tenant_profile.TbTenantProfileService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -59,10 +61,13 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI @TbCoreComponent @RequestMapping("/api") @Slf4j +@RequiredArgsConstructor public class TenantProfileController extends BaseController { private static final String TENANT_PROFILE_INFO_DESCRIPTION = "Tenant Profile Info is a lightweight object that contains only id and name of the profile. "; + private final TbTenantProfileService tbTenantProfileService; + @ApiOperation(value = "Get Tenant Profile (getTenantProfileById)", notes = "Fetch the Tenant Profile object based on the provided Tenant Profile Id. " + SYSTEM_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") @@ -171,14 +176,16 @@ public class TenantProfileController extends BaseController { @RequestBody TenantProfile tenantProfile) throws ThingsboardException { try { boolean newTenantProfile = tenantProfile.getId() == null; + TenantProfile oldProfile; if (newTenantProfile) { accessControlService .checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE); + oldProfile = null; } else { - checkEntityId(tenantProfile.getId(), Operation.WRITE); + oldProfile = checkTenantProfileId(tenantProfile.getId(), Operation.WRITE); } - tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile)); + tenantProfile = checkNotNull(tbTenantProfileService.saveTenantProfile(getTenantId(), tenantProfile, oldProfile)); tenantProfileCache.put(tenantProfile); tbClusterService.onTenantProfileChange(tenantProfile, null); tbClusterService.broadcastEntityStateChangeEvent(TenantId.SYS_TENANT_ID, tenantProfile.getId(), diff --git a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java index 006c9025ba..37556d8b95 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java @@ -19,15 +19,23 @@ import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueClusterService; import org.thingsboard.server.queue.util.TbCoreComponent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + @Slf4j @Service @TbCoreComponent @@ -141,4 +149,73 @@ public class DefaultTbQueueService implements TbQueueService { Thread.sleep(3000); } + @Override + public void updateQueuesByTenants(List tenantIds, TenantProfile newTenantProfile, TenantProfile oldTenantProfile) { + + boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); + boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); + + if (!oldIsolated && !newIsolated) { + return; + } + + if (newTenantProfile.equals(oldTenantProfile)) { + return; + } + + Map oldQueues; + Map newQueues; + + if (oldIsolated) { + oldQueues = oldTenantProfile.getProfileData().getQueueConfiguration().stream() + .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); + } else { + oldQueues = Collections.emptyMap(); + } + + if (newIsolated) { + newQueues = newTenantProfile.getProfileData().getQueueConfiguration().stream() + .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); + } else { + newQueues = Collections.emptyMap(); + } + + List toRemove = new ArrayList<>(); + List toCreate = new ArrayList<>(); + List toUpdate = new ArrayList<>(); + + for (String oldQueue : oldQueues.keySet()) { + if (!newQueues.containsKey(oldQueue)) { + toRemove.add(oldQueue); + } + } + + for (String newQueue : newQueues.keySet()) { + if (oldQueues.containsKey(newQueue)) { + toUpdate.add(newQueue); + } else { + toCreate.add(newQueue); + } + } + + tenantIds.forEach(tenantId -> { + toRemove.forEach(q -> deleteQueueByQueueName(tenantId, q)); + + toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key)))); + + toUpdate.forEach(key -> { + Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); + Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, key); + queueToUpdate.setId(foundQueue.getId()); + queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); + + if (queueToUpdate.equals(foundQueue)) { + //Queue not changed + } else { + saveQueue(queueToUpdate); + } + }); + }); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java index 1b37486ba4..c431d242cf 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/queue/TbQueueService.java @@ -15,10 +15,13 @@ */ package org.thingsboard.server.service.entity.queue; +import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; +import java.util.List; + public interface TbQueueService { Queue saveQueue(Queue queue); @@ -26,4 +29,6 @@ public interface TbQueueService { void deleteQueue(TenantId tenantId, QueueId queueId); void deleteQueueByQueueName(TenantId tenantId, String queueName); + + void updateQueuesByTenants(List tenantIds, TenantProfile newTenantProfile, TenantProfile oldTenantProfile); } diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java index 015c88813b..0d6f838372 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java @@ -21,20 +21,13 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; -import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entity.queue.TbQueueService; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Slf4j @Service @@ -44,7 +37,6 @@ public class DefaultTbTenantService implements TbTenantService { private final TenantService tenantService; private final TbQueueService tbQueueService; - private final QueueService queueService; private final TenantProfileService tenantProfileService; private final TbTenantProfileCache tenantProfileCache; @@ -52,84 +44,14 @@ public class DefaultTbTenantService implements TbTenantService { public Tenant saveTenant(Tenant tenant) { boolean updated = tenant.getId() != null; Tenant oldTenant = updated ? tenantService.findTenantById(tenant.getId()) : null; - List queues; - if (updated) { - - } Tenant savedTenant = tenantService.saveTenant(tenant); tenantProfileCache.evict(tenant.getId()); - updateQueuesForTenant(oldTenant, savedTenant); - return savedTenant; - } - public void updateQueuesForTenant(Tenant oldTenant, Tenant newTenant) { TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; - TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, newTenant.getTenantProfileId()); - - TenantId tenantId = newTenant.getId(); - - boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); - boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); - - if (!oldIsolated && !newIsolated) { - return; - } - - if (newTenantProfile.equals(oldTenantProfile)) { - return; - } - - Map oldQueues; - Map newQueues; - - if (oldIsolated) { - oldQueues = oldTenantProfile.getProfileData().getQueueConfiguration().stream() - .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); - } else { - oldQueues = Collections.emptyMap(); - } - - if (newIsolated) { - newQueues = newTenantProfile.getProfileData().getQueueConfiguration().stream() - .collect(Collectors.toMap(TenantProfileQueueConfiguration::getName, q -> q)); - } else { - newQueues = Collections.emptyMap(); - } - - List toRemove = new ArrayList<>(); - List toCreate = new ArrayList<>(); - List toUpdate = new ArrayList<>(); - - for (String oldQueue : oldQueues.keySet()) { - if (!newQueues.containsKey(oldQueue)) { - toRemove.add(oldQueue); - } - } - - for (String newQueue : newQueues.keySet()) { - if (oldQueues.containsKey(newQueue)) { - toUpdate.add(newQueue); - } else { - toCreate.add(newQueue); - } - } - - toRemove.forEach(q -> tbQueueService.deleteQueueByQueueName(tenantId, q)); - - toCreate.forEach(key -> tbQueueService.saveQueue(new Queue(tenantId, newQueues.get(key)))); - - toUpdate.forEach(key -> { - Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); - Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, key); - queueToUpdate.setId(foundQueue.getId()); - queueToUpdate.setCreatedTime(foundQueue.getCreatedTime()); - - if (queueToUpdate.equals(foundQueue)) { - //Queue not changed - } else { - tbQueueService.saveQueue(queueToUpdate); - } - }); + TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId()); + tbQueueService.updateQueuesByTenants(Collections.singletonList(savedTenant.getTenantId()), newTenantProfile, oldTenantProfile); + return savedTenant; } + } diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/DefaultTbTenantProfileService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/DefaultTbTenantProfileService.java new file mode 100644 index 0000000000..2a01ddfed6 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/DefaultTbTenantProfileService.java @@ -0,0 +1,50 @@ +/** + * 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.entity.tenant_profile; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.tenant.TenantProfileService; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entity.queue.TbQueueService; + +import java.util.List; + +@Slf4j +@Service +@TbCoreComponent +@AllArgsConstructor +public class DefaultTbTenantProfileService implements TbTenantProfileService { + private final TbQueueService queueService; + private final TenantProfileService tenantProfileService; + private final TenantService tenantService; + + @Override + public TenantProfile saveTenantProfile(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) { + TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(tenantId, tenantProfile); + + if (oldTenantProfile != null && savedTenantProfile.isIsolatedTbRuleEngine()) { + List tenantIds = tenantService.findTenantIdsByTenantProfileId(savedTenantProfile.getId()); + queueService.updateQueuesByTenants(tenantIds, savedTenantProfile, oldTenantProfile); + } + + return savedTenantProfile; + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/TbTenantProfileService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/TbTenantProfileService.java new file mode 100644 index 0000000000..0764319d03 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant_profile/TbTenantProfileService.java @@ -0,0 +1,23 @@ +/** + * 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.entity.tenant_profile; + +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.TenantId; + +public interface TbTenantProfileService { + TenantProfile saveTenantProfile(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile); +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index b4bf769944..fbb9dfa0e1 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -19,9 +19,12 @@ import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import java.util.List; + public interface TenantService { Tenant findTenantById(TenantId tenantId); @@ -38,5 +41,7 @@ public interface TenantService { PageData findTenantInfos(PageLink pageLink); + List findTenantIdsByTenantProfileId(TenantProfileId tenantProfileId); + void deleteTenants(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java index e7a1961fab..ea4060aa44 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java @@ -21,6 +21,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.DaoUtil; @@ -29,8 +30,10 @@ import org.thingsboard.server.dao.model.sql.TenantInfoEntity; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.tenant.TenantDao; +import java.util.List; import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** @@ -80,4 +83,10 @@ public class JpaTenantDao extends JpaAbstractSearchTextDao return DaoUtil.pageToPageData(tenantRepository.findTenantsIds(DaoUtil.toPageable(pageLink))).mapData(TenantId::fromUUID); } + @Override + public List findTenantIdsByTenantProfileId(TenantProfileId tenantProfileId) { + return tenantRepository.findTenantIdsByTenantProfileId(tenantProfileId.getId()).stream() + .map(TenantId::fromUUID) + .collect(Collectors.toList()); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java index 4ae1278bec..8aa86a535a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java @@ -23,6 +23,7 @@ import org.springframework.data.repository.query.Param; import org.thingsboard.server.dao.model.sql.TenantEntity; import org.thingsboard.server.dao.model.sql.TenantInfoEntity; +import java.util.List; import java.util.UUID; /** @@ -54,4 +55,7 @@ public interface TenantRepository extends PagingAndSortingRepository findTenantsIds(Pageable pageable); + @Query("SELECT t.id FROM TenantEntity t where t.tenantProfileId = :tenantProfileId") + List findTenantIdsByTenantProfileId(@Param("tenantProfileId") UUID tenantProfileId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java index 94ca9c8c1e..e08ed4745f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java @@ -18,10 +18,12 @@ package org.thingsboard.server.dao.tenant; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; +import java.util.List; import java.util.UUID; public interface TenantDao extends Dao { @@ -49,4 +51,5 @@ public interface TenantDao extends Dao { PageData findTenantsIds(PageLink pageLink); + List findTenantIdsByTenantProfileId(TenantProfileId tenantProfileId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index dcacaba478..187c87f1d3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -20,12 +20,12 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.asset.AssetService; @@ -48,6 +48,8 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.widget.WidgetsBundleService; +import java.util.List; + import static org.thingsboard.server.dao.service.Validator.validateId; @Service @@ -183,6 +185,12 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe return tenantDao.findTenantInfosByRegion(TenantId.SYS_TENANT_ID, DEFAULT_TENANT_REGION, pageLink); } + @Override + public List findTenantIdsByTenantProfileId(TenantProfileId tenantProfileId) { + log.trace("Executing findTenantsByTenantProfileId [{}]", tenantProfileId); + return tenantDao.findTenantIdsByTenantProfileId(tenantProfileId); + } + @Override public void deleteTenants() { log.trace("Executing deleteTenants"); From 547713f30a9b4ab4a9c806fb5922a4de65122ad6 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 2 May 2022 23:44:43 +0200 Subject: [PATCH 16/58] update device profiles queue by tenant profile --- .../entity/queue/DefaultTbQueueService.java | 85 +++++++++++++++---- .../queue/DefaultTbClusterService.java | 44 +++++----- .../queue/DefaultTbCoreConsumerService.java | 6 +- .../DefaultTbRuleEngineConsumerService.java | 4 +- .../processing/AbstractConsumerService.java | 7 +- .../queue/discovery/HashPartitionService.java | 5 ++ .../queue/discovery/PartitionService.java | 2 + .../queue/discovery/QueueRoutingInfo.java | 2 +- .../service/DefaultTransportService.java | 1 + 9 files changed, 111 insertions(+), 45 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java index 37556d8b95..e58c4450fb 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java @@ -19,15 +19,19 @@ import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.queue.TbQueueAdmin; -import org.thingsboard.server.queue.TbQueueClusterService; import org.thingsboard.server.queue.util.TbCoreComponent; import java.util.ArrayList; @@ -41,9 +45,12 @@ import java.util.stream.Collectors; @TbCoreComponent @AllArgsConstructor public class DefaultTbQueueService implements TbQueueService { + private static final String MAIN = "Main"; + private final QueueService queueService; - private final TbQueueClusterService queueClusterService; + private final TbClusterService tbClusterService; private final TbQueueAdmin tbQueueAdmin; + private final DeviceProfileService deviceProfileService; @Override public Queue saveQueue(Queue queue) { @@ -90,8 +97,8 @@ public class DefaultTbQueueService implements TbQueueService { } } - if (queueClusterService != null) { - queueClusterService.onQueueChange(queue); + if (tbClusterService != null) { + tbClusterService.onQueueChange(queue); } } @@ -106,13 +113,13 @@ public class DefaultTbQueueService implements TbQueueService { tbQueueAdmin.createTopicIfNotExists( new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } - if (queueClusterService != null) { - queueClusterService.onQueueChange(queue); + if (tbClusterService != null) { + tbClusterService.onQueueChange(queue); } } else { log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); - if (queueClusterService != null) { - queueClusterService.onQueueChange(queue); + if (tbClusterService != null) { + tbClusterService.onQueueChange(queue); } await(); for (int i = currentPartitions; i < oldPartitions; i++) { @@ -120,14 +127,14 @@ public class DefaultTbQueueService implements TbQueueService { new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } } - } else if (!oldQueue.equals(queue) && queueClusterService != null) { - queueClusterService.onQueueChange(queue); + } else if (!oldQueue.equals(queue) && tbClusterService != null) { + tbClusterService.onQueueChange(queue); } } private void onQueueDeleted(TenantId tenantId, Queue queue) { - if (queueClusterService != null) { - queueClusterService.onQueueDelete(queue); + if (tbClusterService != null) { + tbClusterService.onQueueDelete(queue); await(); } // queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); @@ -151,7 +158,6 @@ public class DefaultTbQueueService implements TbQueueService { @Override public void updateQueuesByTenants(List tenantIds, TenantProfile newTenantProfile, TenantProfile oldTenantProfile) { - boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); @@ -199,9 +205,35 @@ public class DefaultTbQueueService implements TbQueueService { } tenantIds.forEach(tenantId -> { - toRemove.forEach(q -> deleteQueueByQueueName(tenantId, q)); + Map> deviceProfileQueues; + + if (oldTenantProfile != null && !newTenantProfile.getId().equals(oldTenantProfile.getId()) || !toRemove.isEmpty()) { + List 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 createdQueues = toCreate.stream() + .map(key -> saveQueue(new Queue(tenantId, newQueues.get(key)))) + .collect(Collectors.toMap(Queue::getName, Queue::getId)); - toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key)))); + // 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 -> { Queue queueToUpdate = new Queue(tenantId, newQueues.get(key)); @@ -215,7 +247,30 @@ public class DefaultTbQueueService implements TbQueueService { saveQueue(queueToUpdate); } }); + + toRemove.forEach(q -> { + Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q); + QueueId queueIdForRemove = queue.getId(); + if (deviceProfileQueues.containsKey(queueIdForRemove)) { + Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, q); + if (foundQueue == null) { + foundQueue = queueService.findQueueByTenantIdAndName(tenantId, MAIN); + } + QueueId newQueueId = foundQueue.getId(); + deviceProfileQueues.get(queueIdForRemove).stream() + .peek(dp -> dp.setDefaultQueueId(newQueueId)) + .forEach(this::saveDeviceProfile); + } + deleteQueue(tenantId, queueIdForRemove); + }); }); } + //TODO: remove after implementing TbDeviceProfileService + private void saveDeviceProfile(DeviceProfile deviceProfile) { + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); + tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), savedDeviceProfile.getId(), ComponentLifecycleEvent.UPDATED); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index f1ce95f166..2806c35cda 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -86,6 +86,8 @@ public class DefaultTbClusterService implements TbClusterService { private boolean statsEnabled; @Value("${edges.enabled}") protected boolean edgesEnabled; + @Value("${service.type:monolith}") + private String serviceType; private final AtomicInteger toCoreMsgs = new AtomicInteger(0); private final AtomicInteger toCoreNfs = new AtomicInteger(0); @@ -503,10 +505,10 @@ public class DefaultTbClusterService implements TbClusterService { .setPartitions(queue.getPartitions()) .build(); - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); - ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); - doSendQueueNotifications(transportMsg, coreMsg, ruleEngineMsg); + ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueUpdateMsg(queueUpdateMsg).build(); + doSendQueueNotifications(ruleEngineMsg, coreMsg, transportMsg); } @Override @@ -521,32 +523,32 @@ public class DefaultTbClusterService implements TbClusterService { .setQueueName(queue.getName()) .build(); - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); - ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); ToRuleEngineNotificationMsg ruleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); - doSendQueueNotifications(transportMsg, coreMsg, ruleEngineMsg); + ToCoreNotificationMsg coreMsg = ToCoreNotificationMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setQueueDeleteMsg(queueDeleteMsg).build(); + doSendQueueNotifications(ruleEngineMsg, coreMsg, transportMsg); } - private void doSendQueueNotifications(ToTransportMsg transportMsg, ToCoreNotificationMsg coreMsg, ToRuleEngineNotificationMsg ruleEngineMsg) { - Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); - for (TransportProtos.ServiceInfo transportService : tbTransportServices) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); - producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), null); - toTransportNfs.incrementAndGet(); - } - - Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); - for (TransportProtos.ServiceInfo coreService : tbCoreServices) { - TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); - producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), null); - toCoreNfs.incrementAndGet(); - } - + private void doSendQueueNotifications(ToRuleEngineNotificationMsg ruleEngineMsg, ToCoreNotificationMsg coreMsg, ToTransportMsg transportMsg) { Set tbRuleEngineServices = partitionService.getAllServices(ServiceType.TB_RULE_ENGINE); for (TransportProtos.ServiceInfo ruleEngineService : tbRuleEngineServices) { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, ruleEngineService.getServiceId()); producerProvider.getRuleEngineNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), ruleEngineMsg), null); toRuleEngineNfs.incrementAndGet(); } + if (!serviceType.equals("monolith")) { + Set tbCoreServices = partitionService.getAllServices(ServiceType.TB_CORE); + for (TransportProtos.ServiceInfo coreService : tbCoreServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, coreService.getServiceId()); + producerProvider.getTbCoreNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), coreMsg), null); + toCoreNfs.incrementAndGet(); + } + Set tbTransportServices = partitionService.getAllServices(ServiceType.TB_TRANSPORT); + for (TransportProtos.ServiceInfo transportService : tbTransportServices) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_TRANSPORT, transportService.getServiceId()); + producerProvider.getTransportNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), transportMsg), null); + toTransportNfs.incrementAndGet(); + } + } } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 7113272187..bec0dceed3 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -117,7 +117,6 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> usageStatsConsumer; private final TbQueueConsumer> firmwareStatesConsumer; @@ -139,7 +138,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> nfConsumer; public AbstractConsumerService(ActorSystemContext actorContext, DataDecodingEncodingService encodingService, TbTenantProfileCache tenantProfileCache, TbDeviceProfileCache deviceProfileCache, - TbApiUsageStateService apiUsageStateService, TbQueueConsumer> nfConsumer) { + TbApiUsageStateService apiUsageStateService, PartitionService partitionService, + TbQueueConsumer> nfConsumer) { this.actorContext = actorContext; this.encodingService = encodingService; this.tenantProfileCache = tenantProfileCache; this.deviceProfileCache = deviceProfileCache; this.apiUsageStateService = apiUsageStateService; + this.partitionService = partitionService; this.nfConsumer = nfConsumer; } @@ -166,6 +170,7 @@ public abstract class AbstractConsumerService profileOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); if (profileOpt.isPresent()) { Tenant tenant = profileOpt.get(); + partitionService.removeTenant(tenant.getId()); boolean updated = tenantProfileCache.put(tenant.getId(), tenant.getTenantProfileId()); if (updated) { rateLimitService.update(tenant.getId()); From 41fa5d949bcc508cfd4b0168e78620374930320e Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 3 May 2022 09:01:19 +0200 Subject: [PATCH 17/58] fixed NP --- .../server/service/entity/tenant/DefaultTbTenantService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java index 0d6f838372..ca5bd08354 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java @@ -46,7 +46,7 @@ public class DefaultTbTenantService implements TbTenantService { Tenant oldTenant = updated ? tenantService.findTenantById(tenant.getId()) : null; Tenant savedTenant = tenantService.saveTenant(tenant); - tenantProfileCache.evict(tenant.getId()); + tenantProfileCache.evict(savedTenant.getId()); TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId()); From 659cb0d3d63cdee6e8dd78f3165cf80134eacc65 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 3 May 2022 11:09:27 +0200 Subject: [PATCH 18/58] fixed isolated tenant tests --- .../BaseTenantProfileControllerTest.java | 33 +++++++++++++++++-- .../service/BaseTenantProfileServiceTest.java | 24 ++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java index d8efb76f95..774848715e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java @@ -24,11 +24,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.ProcessingStrategyType; +import org.thingsboard.server.common.data.queue.SubmitStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategyType; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.tenant.TenantProfileService; import java.util.ArrayList; @@ -44,9 +49,6 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController private IdComparator idComparator = new IdComparator<>(); private IdComparator tenantProfileInfoIdComparator = new IdComparator<>(); - @Autowired - private TenantProfileService tenantProfileService; - @Test public void testSaveTenantProfile() throws Exception { loginSysAdmin(); @@ -141,6 +143,7 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class); savedTenantProfile.setIsolatedTbRuleEngine(true); + addMainQueueConfig(savedTenantProfile); doPost("/api/tenantProfile", savedTenantProfile).andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Can't update isolatedTbRuleEngine property"))); } @@ -295,4 +298,28 @@ public abstract class BaseTenantProfileControllerTest extends AbstractController tenantProfile.setIsolatedTbRuleEngine(false); return tenantProfile; } + + private void addMainQueueConfig(TenantProfile tenantProfile) { + 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); + } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java index ae9459ccae..210105c73c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java @@ -171,6 +171,7 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest { TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"); TenantProfile savedTenantProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); savedTenantProfile.setIsolatedTbRuleEngine(true); + addMainQueueConfig(savedTenantProfile); tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile); } @@ -300,4 +301,27 @@ public abstract class BaseTenantProfileServiceTest extends AbstractServiceTest { return tenantProfile; } + private void addMainQueueConfig(TenantProfile tenantProfile) { + 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); + } } From 141dc735f313ed6d7dbf311fc3ea47a2e2555714 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 4 May 2022 10:05:16 +0200 Subject: [PATCH 19/58] fixed removind queue config if queue used in device profile --- .../entity/queue/DefaultTbQueueService.java | 2 +- .../queue/discovery/HashPartitionService.java | 31 +++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java index e58c4450fb..655d4beb88 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/queue/DefaultTbQueueService.java @@ -253,7 +253,7 @@ public class DefaultTbQueueService implements TbQueueService { QueueId queueIdForRemove = queue.getId(); if (deviceProfileQueues.containsKey(queueIdForRemove)) { Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, q); - if (foundQueue == null) { + if (foundQueue == null || queue.equals(foundQueue)) { foundQueue = queueService.findQueueByTenantIdAndName(tenantId, MAIN); } QueueId newQueueId = foundQueue.getId(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 8e83af2600..246fac00af 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -141,20 +141,20 @@ public class HashPartitionService implements PartitionService { public void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueUpdateMsg.getQueueName(), tenantId); - partitionTopicsMap.put(queueKey, queueUpdateMsg.getQueueTopic()); - partitionSizesMap.put(queueKey, queueUpdateMsg.getPartitions()); QueueRoutingInfo queue = new QueueRoutingInfo(queueUpdateMsg); queuesById.put(queue.getQueueId(), queue); + partitionTopicsMap.put(queueKey, queueUpdateMsg.getQueueTopic()); + partitionSizesMap.put(queueKey, queueUpdateMsg.getPartitions()); } @Override public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); - partitionTopicsMap.remove(queueKey); - partitionSizesMap.remove(queueKey); queuesById.remove(new QueueId(new UUID(queueDeleteMsg.getQueueIdMSB(), queueDeleteMsg.getQueueIdLSB()))); myPartitions.remove(queueKey); + partitionTopicsMap.remove(queueKey); + partitionSizesMap.remove(queueKey); } @Override @@ -166,14 +166,29 @@ public class HashPartitionService implements PartitionService { public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) { QueueKey queueKey; if (queueId == null) { - queueKey = isIsolated(serviceType, tenantId) ? new QueueKey(serviceType, tenantId) : new QueueKey(serviceType); + queueKey = getMainQueueKey(serviceType, tenantId); } else { - queueKey = new QueueKey(serviceType, queuesById.get(queueId)); + QueueRoutingInfo queueRoutingInfo = queuesById.get(queueId); + + //TODO: replace if we can notify CheckPoint rule nodes about queue changes + if (queueRoutingInfo == null) { + log.warn("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.warn("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) { int hash = hashFunction.newHasher() .putLong(entityId.getId().getMostSignificantBits()) @@ -357,6 +372,10 @@ public class HashPartitionService implements PartitionService { } } + private TenantId getIsolatedOrSystemTenantId(ServiceType serviceType, TenantId tenantId) { + return isIsolated(serviceType, tenantId) ? tenantId : TenantId.SYS_TENANT_ID; + } + private void logServiceInfo(TransportProtos.ServiceInfo server) { log.info("[{}] Found common server: [{}]", server.getServiceId(), server.getServiceTypesList()); } From 7ef761393924b8e35ce6a22af7475653b08f3dd3 Mon Sep 17 00:00:00 2001 From: fe-dev Date: Thu, 5 May 2022 11:02:45 +0300 Subject: [PATCH 20/58] UI: Refactoring queue --- ui-ngx/src/app/core/http/entity.service.ts | 3 +- ui-ngx/src/app/modules/common/modules-map.ts | 4 +- .../home/components/home-components.module.ts | 6 +- .../add-device-profile-dialog.component.ts | 3 +- .../queue/tenant-profile-queue.component.html | 194 ------------------ .../tenant-profile-queues.component.html | 36 +++- .../tenant-profile-queues.component.scss | 8 +- .../queue/tenant-profile-queues.component.ts | 32 ++- .../tenant-profile-data.component.html | 17 +- .../profile/tenant-profile.component.html | 23 ++- .../profile/tenant-profile.component.ts | 2 +- .../queue/queue-form.component.html | 171 +++++++++++++++ .../queue-form.component.scss} | 0 .../queue-form.component.ts} | 57 +++-- .../wizard/device-wizard-dialog.component.ts | 2 +- .../home/pages/admin/admin-routing.module.ts | 36 +++- .../pages/admin/queue/queue.component.html | 181 ++-------------- .../pages/admin/queue/queue.component.scss | 22 -- .../home/pages/admin/queue/queue.component.ts | 109 ++-------- .../queue/queues-table-config.resolver.ts | 33 ++- .../queue/queue-autocomplete.component.html | 2 +- .../queue/queue-autocomplete.component.ts | 10 +- ui-ngx/src/app/shared/models/device.models.ts | 2 +- .../app/shared/models/entity-type.models.ts | 3 +- .../assets/locale/locale.constant-en_US.json | 6 +- 25 files changed, 382 insertions(+), 580 deletions(-) delete mode 100644 ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html create mode 100644 ui-ngx/src/app/modules/home/components/queue/queue-form.component.html rename ui-ngx/src/app/modules/home/components/{profile/queue/tenant-profile-queue.component.scss => queue/queue-form.component.scss} (100%) rename ui-ngx/src/app/modules/home/components/{profile/queue/tenant-profile-queue.component.ts => queue/queue-form.component.ts} (78%) delete mode 100644 ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 71e2a3de95..0b0c23edee 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -87,8 +87,7 @@ import { bodyContentEdgeEventActionTypes, Edge, EdgeEvent, EdgeEventType } from import { RuleChainMetaData, RuleChainType } from '@shared/models/rule-chain.models'; import { WidgetService } from '@core/http/widget.service'; import { DeviceProfileService } from '@core/http/device-profile.service'; -import { QueueService } from "@core/http/queue.service"; -import { ServiceType } from "@shared/models/queue.models"; +import { QueueService } from '@core/http/queue.service'; @Injectable({ providedIn: 'root' diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index bfc8f60604..a1fca3f603 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -288,7 +288,7 @@ import * as AlarmDurationPredicateValueComponent from '@home/components/profile/ import * as DashboardImageDialogComponent from '@home/components/dashboard-page/dashboard-image-dialog.component'; import * as WidgetContainerComponent from '@home/components/widget/widget-container.component'; import * as TenantProfileQueuesComponent from '@home/components/profile/queue/tenant-profile-queues.component'; -import { TenantProfileQueueComponent } from '@home/components/profile/queue/tenant-profile-queue.component'; +import * as QueueFormComponent from '@home/components/queue/queue-form.component'; import { IModulesMap } from '@modules/common/modules-map.models'; @@ -573,7 +573,7 @@ class ModulesMap implements IModulesMap { '@home/components/dashboard-page/dashboard-image-dialog.component': DashboardImageDialogComponent, '@home/components/widget/widget-container.component': WidgetContainerComponent, '@home/components/profile/queue/tenant-profile-queues.component': TenantProfileQueuesComponent, - '@home/components/profile/queue/tenant-profile-queue.component': TenantProfileQueueComponent + '@home/components/queue/queue-form.component': QueueFormComponent }; init() { diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 282a494026..6039cc0553 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -149,7 +149,7 @@ import { import { DashboardStateComponent } from '@home/components/dashboard-page/dashboard-state.component'; import { EntityDetailsPageComponent } from '@home/components/entity/entity-details-page.component'; import { TenantProfileQueuesComponent } from '@home/components/profile/queue/tenant-profile-queues.component'; -import { TenantProfileQueueComponent } from '@home/components/profile/queue/tenant-profile-queue.component'; +import { QueueFormComponent } from '@home/components/queue/queue-form.component'; @NgModule({ declarations: @@ -271,7 +271,7 @@ import { TenantProfileQueueComponent } from '@home/components/profile/queue/tena EmbedDashboardDialogComponent, DisplayWidgetTypesPanelComponent, TenantProfileQueuesComponent, - TenantProfileQueueComponent + QueueFormComponent ], imports: [ CommonModule, @@ -386,7 +386,7 @@ import { TenantProfileQueueComponent } from '@home/components/profile/queue/tena EmbedDashboardDialogComponent, DisplayWidgetTypesPanelComponent, TenantProfileQueuesComponent, - TenantProfileQueueComponent + QueueFormComponent ], providers: [ WidgetComponentService, diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index 2d80e9a25b..79c5a74db3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -50,7 +50,7 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { deepTrim } from '@core/utils'; import { ServiceType } from '@shared/models/queue.models'; import { DashboardId } from '@shared/models/id/dashboard-id'; -import { QueueId } from "@shared/models/id/queue-id"; +import { QueueId } from '@shared/models/id/queue-id'; export interface AddDeviceProfileDialogData { deviceProfileName: string; @@ -188,7 +188,6 @@ export class AddDeviceProfileDialogComponent extends name: this.deviceProfileDetailsFormGroup.get('name').value, type: this.deviceProfileDetailsFormGroup.get('type').value, image: this.deviceProfileDetailsFormGroup.get('image').value, - // defaultQueueId: this.deviceProfileDetailsFormGroup.get('defaultQueueId').value, transportType: this.transportConfigFormGroup.get('transportType').value, provisionType: deviceProvisionConfiguration.type, provisionDeviceKey, diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html deleted file mode 100644 index 07bcb5d9e8..0000000000 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.html +++ /dev/null @@ -1,194 +0,0 @@ - - - -
- -
- {{ queueTitle }} -
-
- - -
-
- -
- - - admin.queue-name - - - {{ 'queue.name-required' | translate }} - - - - queue.poll-interval - - - {{ 'queue.poll-interval-required' | translate }} - - - {{ 'queue.poll-interval-min-value' | translate }} - - - - queue.partitions - - - {{ 'queue.partitions-required' | translate }} - - - {{ 'queue.partitions-min-value' | translate }} - - - - -
{{ 'queue.consumer-per-partition' | translate }}
-
{{'queue.consumer-per-partition-hint' | translate}}
-
- - - queue.processing-timeout - - - {{ 'queue.pack-processing-timeout-required' | translate }} - - - {{ 'queue.pack-processing-timeout-min-value' | translate }} - - - - - - - queue.submit-strategy - - - -
- - queue.submit-strategy - - - {{ strategy }} - - - - {{ 'queue.submit-strategy-type-required' | translate }} - - - - queue.batch-size - - - {{ 'queue.batch-size-required' | translate }} - - - {{ 'queue.batch-size-min-value' | translate }} - - -
-
-
- - - - queue.processing-strategy - - - -
- - queue.processing-strategy - - - {{ strategy }} - - - - {{ 'queue.processing-strategy-type-required' | translate }} - - - - queue.retries - - - {{ 'queue.retries-required' | translate }} - - - {{ 'queue.retries-min-value' | translate }} - - - - queue.failure-percentage - - - {{ 'queue.failure-percentage-required' | translate }} - - - {{ 'queue.failure-percentage-min-value' | translate }} - - - {{ 'queue.failure-percentage-max-value' | translate }} - - - - queue.pause-between-retries - - - {{ 'queue.pause-between-retries-required' | translate }} - - - {{ 'queue.pause-between-retries-min-value' | translate }} - - - - queue.max-pause-between-retries - - - {{ 'queue.max-pause-between-retries-required' | translate }} - - - {{ 'queue.max-pause-between-retries-min-value' | translate }} - - -
-
-
-
-
-
-
diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html index 59b7e063a1..34c43f240c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.html @@ -17,18 +17,34 @@ -->
- -
- - -
+ + + +
+ + {{ getName(queuesControl.value.name) }} + + + +
+
+ + + + +
-
+
tenant-profile.no-queue
diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss index 9702d807a6..189badf9fd 100644 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.scss @@ -13,15 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import '../../../../../../scss/constants'; :host { .tb-tenant-profile-queues { - &.mat-padding { - padding: 8px; - @media #{$mat-gt-sm} { - padding: 16px; - } + .mat-expansion-panel-body { + padding-bottom: 0 !important; } } diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts index abcde44419..a403f8e82e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts @@ -14,16 +14,16 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy } from '@angular/core'; import { AbstractControl, ControlValueAccessor, FormArray, FormBuilder, - FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, + ValidationErrors, Validator, Validators } from '@angular/forms'; @@ -32,6 +32,7 @@ import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Subscription } from 'rxjs'; import { QueueInfo } from '@shared/models/queue.models'; +import { UtilsService } from '@core/services/utils.service'; @Component({ selector: 'tb-tenant-profile-queues', @@ -50,7 +51,7 @@ import { QueueInfo } from '@shared/models/queue.models'; } ] }) -export class TenantProfileQueuesComponent implements ControlValueAccessor, OnInit, Validator { +export class TenantProfileQueuesComponent implements ControlValueAccessor, Validator, OnDestroy { tenantProfileQueuesFormGroup: FormGroup; newQueue = false; @@ -67,11 +68,12 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, OnIni @Input() disabled: boolean; - private valueChangeSubscription: Subscription = null; + private valueChangeSubscription$: Subscription = null; private propagateChange = (v: any) => { }; constructor(private store: Store, + private utils: UtilsService, private fb: FormBuilder) { } @@ -79,6 +81,12 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, OnIni this.propagateChange = fn; } + ngOnDestroy() { + if (this.valueChangeSubscription$) { + this.valueChangeSubscription$.unsubscribe(); + } + } + registerOnTouched(fn: any): void { } @@ -88,7 +96,7 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, OnIni }); } - queuesFormArray(): FormArray { + get queuesFormArray(): FormArray { return this.tenantProfileQueuesFormGroup.get('queues') as FormArray; } @@ -102,8 +110,8 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, OnIni } writeValue(queues: Array | null): void { - if (this.valueChangeSubscription) { - this.valueChangeSubscription.unsubscribe(); + if (this.valueChangeSubscription$) { + this.valueChangeSubscription$.unsubscribe(); } const queuesControls: Array = []; if (queues) { @@ -117,7 +125,7 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, OnIni } else { this.tenantProfileQueuesFormGroup.enable({emitEvent: false}); } - this.valueChangeSubscription = this.tenantProfileQueuesFormGroup.valueChanges.subscribe(() => { + this.valueChangeSubscription$ = this.tenantProfileQueuesFormGroup.valueChanges.subscribe(value => { this.updateModel(); }); } @@ -163,14 +171,18 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, OnIni } } - public validate(c: FormControl) { - return (this.tenantProfileQueuesFormGroup.valid) ? null : { + public validate(c: AbstractControl): ValidationErrors | null { + return this.tenantProfileQueuesFormGroup.valid ? null : { queues: { valid: false, }, }; } + getName(value) { + return this.utils.customTranslation(value, value); + } + private updateModel() { const queues: Array = this.tenantProfileQueuesFormGroup.get('queues').value; this.propagateChange(queues); diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html index 81ca768911..5cf574a0e4 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html @@ -16,17 +16,8 @@ -->
- - - -
tenant-profile.profile-configuration
-
-
- - - - -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index 4b511037e7..789ba8590a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -68,13 +68,13 @@
{{'tenant.isolated-tb-rule-engine-details' | translate}}
- + -
{{'tenant-profile.queues-with-count' | translate: + {{'tenant-profile.queues-with-count' | translate: {count: entityForm.get('profileData').get('queueConfiguration').value ? - entityForm.get('profileData').get('queueConfiguration').value.length : 0} }}
+ entityForm.get('profileData').get('queueConfiguration').value.length : 0} }}
@@ -83,10 +83,19 @@ >
- - + + + +
tenant-profile.profile-configuration
+
+
+ + + + +
tenant-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts index 285cecc5e6..6a57ee57d0 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts @@ -81,7 +81,7 @@ export class TenantProfileComponent extends EntityComponent { profileData: this.fb.group({ configuration: [entity && !this.isAdd ? entity?.profileData.configuration : createTenantProfileConfiguration(TenantProfileType.DEFAULT), []], - queueConfiguration: [null, []] + queueConfiguration: [entity && !this.isAdd ? entity?.profileData.queueConfiguration : null, []] }), description: [entity ? entity.description : '', []], } diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html new file mode 100644 index 0000000000..9ea9720b7b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html @@ -0,0 +1,171 @@ + + +
+ + admin.queue-name + + + {{ 'queue.name-required' | translate }} + + + + queue.poll-interval + + + {{ 'queue.poll-interval-required' | translate }} + + + {{ 'queue.poll-interval-min-value' | translate }} + + + + queue.partitions + + + {{ 'queue.partitions-required' | translate }} + + + {{ 'queue.partitions-min-value' | translate }} + + + +
{{ 'queue.consumer-per-partition' | translate }}
+
{{'queue.consumer-per-partition-hint' | translate}}
+
+ + queue.processing-timeout + + + {{ 'queue.pack-processing-timeout-required' | translate }} + + + {{ 'queue.pack-processing-timeout-min-value' | translate }} + + + + + + + queue.submit-strategy + + + +
+ + queue.submit-strategy + + + {{ strategy }} + + + + {{ 'queue.submit-strategy-type-required' | translate }} + + + + queue.batch-size + + + {{ 'queue.batch-size-required' | translate }} + + + {{ 'queue.batch-size-min-value' | translate }} + + +
+
+
+ + + + queue.processing-strategy + + + +
+ + queue.processing-strategy + + + {{ strategy }} + + + + {{ 'queue.processing-strategy-type-required' | translate }} + + + + queue.retries + + + {{ 'queue.retries-required' | translate }} + + + {{ 'queue.retries-min-value' | translate }} + + + + queue.failure-percentage + + + {{ 'queue.failure-percentage-required' | translate }} + + + {{ 'queue.failure-percentage-min-value' | translate }} + + + {{ 'queue.failure-percentage-max-value' | translate }} + + + + queue.pause-between-retries + + + {{ 'queue.pause-between-retries-required' | translate }} + + + {{ 'queue.pause-between-retries-min-value' | translate }} + + + + queue.max-pause-between-retries + + + {{ 'queue.max-pause-between-retries-required' | translate }} + + + {{ 'queue.max-pause-between-retries-min-value' | translate }} + + +
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.scss rename to ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts similarity index 78% rename from ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts rename to ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts index 7eb0062293..c3d4b1273a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queue.component.ts +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -25,46 +25,40 @@ import { Validator, Validators } from '@angular/forms'; -import { DeviceProfileAlarm } from '@shared/models/device.models'; import { MatDialog } from '@angular/material/dialog'; import { UtilsService } from '@core/services/utils.service'; -import { QueueProcessingStrategyTypes, QueueSubmitStrategyTypes } from '@shared/models/queue.models'; +import { QueueInfo, QueueProcessingStrategyTypes, QueueSubmitStrategyTypes } from '@shared/models/queue.models'; +import { isDefinedAndNotNull } from '@core/utils'; @Component({ - selector: 'tb-tenant-profile-queue', - templateUrl: './tenant-profile-queue.component.html', - styleUrls: ['./tenant-profile-queue.component.scss'], + selector: 'tb-queue-form', + templateUrl: './queue-form.component.html', + styleUrls: ['./queue-form.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => TenantProfileQueueComponent), + useExisting: forwardRef(() => QueueFormComponent), multi: true }, { provide: NG_VALIDATORS, - useExisting: forwardRef(() => TenantProfileQueueComponent), + useExisting: forwardRef(() => QueueFormComponent), multi: true, } ] }) -export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit, Validator { +export class QueueFormComponent implements ControlValueAccessor, OnInit, Validator { @Input() disabled: boolean; - @Output() - removeQueue = new EventEmitter(); - @Input() - expanded = false; + newQueue = false; @Input() - mainQueue = false; + systemQueue = false; - @Input() - newQueue = false; - - private modelValue: DeviceProfileAlarm; + private modelValue: QueueInfo; queueFormGroup: FormGroup; @@ -106,7 +100,7 @@ export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit packProcessingTimeout: [2000, [Validators.min(1), Validators.required]], submitStrategy: this.fb.group({ type: [null, [Validators.required]], - batchSize: [0, [Validators.min(1), Validators.required]], + batchSize: [null], }), processingStrategy: this.fb.group({ type: [null, [Validators.required]], @@ -141,20 +135,20 @@ export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit } } - writeValue(value: DeviceProfileAlarm): void { + writeValue(value: QueueInfo): void { this.propagateChangePending = false; this.modelValue = value; - if (!this.modelValue.alarmType) { - this.expanded = true; + if (isDefinedAndNotNull(this.modelValue)) { + this.queueFormGroup.patchValue(this.modelValue, {emitEvent: false}); } - this.queueFormGroup.reset(this.modelValue || undefined, {emitEvent: false}); + this.submitStrategyTypeChanged(); if (!this.disabled && !this.queueFormGroup.valid) { this.updateModel(); } } public validate(c: FormControl) { - if (c.parent) { + if (c.parent && !this.systemQueue) { const queueName = c.value.name; const profileQueues = []; c.parent.getRawValue().forEach((queue) => { @@ -174,11 +168,6 @@ export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit }; } - get queueTitle(): string { - const queueName = this.queueFormGroup.get('name').value; - return this.utils.customTranslation(queueName, queueName); - } - private updateModel() { const value = this.queueFormGroup.value; this.modelValue = {...this.modelValue, ...value}; @@ -194,12 +183,14 @@ export class TenantProfileQueueComponent implements ControlValueAccessor, OnInit const type: QueueSubmitStrategyTypes = form.get('type').value; const batchSizeField = form.get('batchSize'); if (type === QueueSubmitStrategyTypes.BATCH) { - batchSizeField.enable(); - batchSizeField.patchValue(1000); + batchSizeField.enable({emitEvent: false}); + batchSizeField.patchValue(1000, {emitEvent: false}); + batchSizeField.setValidators([Validators.min(1), Validators.required]); this.hideBatchSize = true; } else { - batchSizeField.patchValue(null); - batchSizeField.disable(); + batchSizeField.patchValue(null, {emitEvent: false}); + batchSizeField.disable({emitEvent: false}); + batchSizeField.clearValidators(); this.hideBatchSize = false; } } diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 1f1a5266ba..b886fe5711 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -49,7 +49,7 @@ import { MediaBreakpoints } from '@shared/models/constants'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { ServiceType } from '@shared/models/queue.models'; import { deepTrim } from '@core/utils'; -import { QueueId } from "@shared/models/id/queue-id"; +import { QueueId } from '@shared/models/id/queue-id'; @Component({ selector: 'tb-device-wizard', diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index 3f8b26f105..e5252f915f 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -187,19 +187,41 @@ const routes: Routes = [ }, { path: 'queues', - component: EntitiesTableComponent, - canDeactivate: [ConfirmOnExitGuard], data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.queues', breadcrumb: { label: 'admin.queues', icon: 'swap_calls' } }, - resolve: { - entitiesTableConfig: QueuesTableConfigResolver - } + children: [ + { + path: '', + component: EntitiesTableComponent, + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.queues' + }, + resolve: { + entitiesTableConfig: QueuesTableConfigResolver + } + }, + { + path: ':entityId', + component: EntityDetailsPageComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + breadcrumb: { + labelFunction: entityDetailsPageBreadcrumbLabelFunction, + icon: 'swap_calls' + } as BreadCrumbConfig, + auth: [Authority.SYS_ADMIN], + title: 'admin.queues' + }, + resolve: { + entitiesTableConfig: QueuesTableConfigResolver + } + } + ] } ] } diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html index 9d7b9ead45..0432f99966 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.html @@ -16,170 +16,33 @@ -->
+ +
+ +
- -
-
-
- - admin.queue-name - - - {{ 'queue.name-required' | translate }} - - - - queue.poll-interval - - - {{ 'queue.poll-interval-required' | translate }} - - - {{ 'queue.poll-interval-min-value' | translate }} - - - - queue.partitions - - - {{ 'queue.partitions-required' | translate }} - - - {{ 'queue.partitions-min-value' | translate }} - - - - -
{{ 'queue.consumer-per-partition' | translate }}
-
{{'queue.consumer-per-partition-hint' | translate}}
-
- - - queue.processing-timeout - - - {{ 'queue.pack-processing-timeout-required' | translate }} - - - {{ 'queue.pack-processing-timeout-min-value' | translate }} - - - - - - - queue.submit-strategy - - - -
- - queue.submit-strategy - - - {{ strategy }} - - - - {{ 'queue.submit-strategy-type-required' | translate }} - - - - queue.batch-size - - - {{ 'queue.batch-size-required' | translate }} - - - {{ 'queue.batch-size-min-value' | translate }} - - -
-
-
- - - - queue.processing-strategy - - - -
- - queue.processing-strategy - - - {{ strategy }} - - - - {{ 'queue.processing-strategy-type-required' | translate }} - - - - queue.retries - - - {{ 'queue.retries-required' | translate }} - - - {{ 'queue.retries-min-value' | translate }} - - - - queue.failure-percentage - - - {{ 'queue.failure-percentage-required' | translate }} - - - {{ 'queue.failure-percentage-min-value' | translate }} - - - {{ 'queue.failure-percentage-max-value' | translate }} - - - - queue.pause-between-retries - - - {{ 'queue.pause-between-retries-required' | translate }} - - - {{ 'queue.pause-between-retries-min-value' | translate }} - - - - queue.max-pause-between-retries - - - {{ 'queue.max-pause-between-retries-required' | translate }} - - - {{ 'queue.max-pause-between-retries-min-value' | translate }} - - -
-
-
-
-
-
+
+ +
diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss deleted file mode 100644 index c87504819e..0000000000 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.scss +++ /dev/null @@ -1,22 +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. - */ -:host ::ng-deep { - .queue-form { - .mat-expansion-panel-body { - padding-bottom: 0 !important; - } - } -} diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts index f436264793..d2fbaa1b77 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queue.component.ts @@ -16,18 +16,19 @@ import { ChangeDetectorRef, Component, Inject } from '@angular/core'; import { EntityType } from '@shared/models/entity-type.models'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup } from '@angular/forms'; import { EntityComponent } from '@home/components/entity/entity.component'; -import { QueueInfo, QueueProcessingStrategyTypes, QueueSubmitStrategyTypes } from '@shared/models/queue.models'; +import { QueueInfo } from '@shared/models/queue.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; +import { ActionNotificationShow } from '@core/notification/notification.actions'; @Component({ selector: 'tb-queue', templateUrl: './queue.component.html', - styleUrls: ['./queue.component.scss'] + styleUrls: [] }) export class QueueComponent extends EntityComponent { entityForm: FormGroup; @@ -36,9 +37,6 @@ export class QueueComponent extends EntityComponent { submitStrategies: string[] = []; processingStrategies: string[] = []; - QueueSubmitStrategyTypes = QueueSubmitStrategyTypes; - hideBatchSize = false; - constructor(protected store: Store, protected translate: TranslateService, @Inject('entity') protected entityValue: QueueInfo, @@ -46,62 +44,16 @@ export class QueueComponent extends EntityComponent { protected cd: ChangeDetectorRef, public fb: FormBuilder) { super(store, fb, entityValue, entitiesTableConfigValue, cd); - this.submitStrategies = Object.values(QueueSubmitStrategyTypes); - this.processingStrategies = Object.values(QueueProcessingStrategyTypes); } ngOnInit() { super.ngOnInit(); - this.entityForm.get('submitStrategy').get('type').valueChanges.subscribe(() => { - this.submitStrategyTypeChanged(); - }); } buildForm(entity: QueueInfo): FormGroup { - return this.fb.group( - { - name: [entity ? entity.name : '', [Validators.required]], - pollInterval: [ - entity && entity.pollInterval ? entity.pollInterval : 25, - [Validators.min(1), Validators.required] - ], - partitions: [ - entity && entity.partitions ? entity.partitions : 10, - [Validators.min(1), Validators.required] - ], - consumerPerPartition: [entity ? entity.consumerPerPartition : false, []], - packProcessingTimeout: [ - entity && entity.packProcessingTimeout ? entity.packProcessingTimeout : 2000, - [Validators.min(1), Validators.required] - ], - submitStrategy: this.fb.group({ - type: [entity ? entity.submitStrategy?.type : null, [Validators.required]], - batchSize: [ - entity && entity.submitStrategy?.batchSize ? entity.submitStrategy?.batchSize : 1000, - [Validators.min(1), Validators.required] - ], - }), - processingStrategy: this.fb.group({ - type: [entity ? entity.processingStrategy?.type : null, [Validators.required]], - retries: [ - entity && entity.processingStrategy?.retries ? entity.processingStrategy?.retries : 3, - [Validators.min(0), Validators.required] - ], - failurePercentage: [ - entity && entity.processingStrategy?.failurePercentage ? entity.processingStrategy?.failurePercentage : 0, - [Validators.min(0), Validators.required, Validators.max(100)] - ], - pauseBetweenRetries: [ - entity && entity.processingStrategy?.pauseBetweenRetries ? entity.processingStrategy?.pauseBetweenRetries : 3, - [Validators.min(1), Validators.required] - ], - maxPauseBetweenRetries: [ - entity && entity.processingStrategy?.maxPauseBetweenRetries ? entity.processingStrategy?.maxPauseBetweenRetries : 3, - [Validators.min(1), Validators.required] - ], - }) - } - ); + return this.fb.group({ + queue: [entity] + }); } hideDelete() { @@ -114,41 +66,22 @@ export class QueueComponent extends EntityComponent { updateForm(entity: QueueInfo) { this.entityForm.patchValue({ - name: entity.name, - pollInterval: entity.pollInterval, - partitions: entity.partitions, - consumerPerPartition: entity.consumerPerPartition, - packProcessingTimeout: entity.packProcessingTimeout, - submitStrategy: { - type: entity.submitStrategy?.type, - batchSize: entity.submitStrategy?.batchSize, - }, - processingStrategy: { - type: entity.processingStrategy?.type, - retries: entity.processingStrategy?.retries, - failurePercentage: entity.processingStrategy?.failurePercentage, - pauseBetweenRetries: entity.processingStrategy?.pauseBetweenRetries, - maxPauseBetweenRetries: entity.processingStrategy?.maxPauseBetweenRetries, - } - }, {emitEvent: true}); + queue: entity + }, {emitEvent: false}); + } - if (!this.isAdd) { - this.entityForm.get('name').disable({emitEvent: false}); - } + prepareFormValue(formValue: any) { + return super.prepareFormValue(formValue.queue); } - submitStrategyTypeChanged() { - const form = this.entityForm.get('submitStrategy') as FormGroup; - const type: QueueSubmitStrategyTypes = form.get('type').value; - const batchSizeField = form.get('batchSize'); - if (type === QueueSubmitStrategyTypes.BATCH) { - batchSizeField.enable(); - batchSizeField.patchValue(1000); - this.hideBatchSize = true; - } else { - batchSizeField.patchValue(null); - batchSizeField.disable(); - this.hideBatchSize = false; - } + onQueueIdCopied($event) { + this.store.dispatch(new ActionNotificationShow( + { + message: this.translate.instant('queue.idCopiedMessage'), + type: 'success', + duration: 750, + verticalPosition: 'bottom', + horizontalPosition: 'right' + })); } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts index aaaac2168f..5af2735a49 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts @@ -15,11 +15,8 @@ /// import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; -import { - EntityTableColumn, - EntityTableConfig -} from '@home/models/entity/entities-table-config.models'; +import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'; +import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { QueueInfo, ServiceType } from '@shared/models/queue.models'; import { select, Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -34,6 +31,7 @@ import { TranslateService } from '@ngx-translate/core'; import { QueueComponent } from './queue.component'; import { QueueService } from '@core/http/queue.service'; import { selectAuthUser } from '@core/auth/auth.selectors'; +import { EntityAction } from '@home/models/entity/entity-component.models'; @Injectable() export class QueuesTableConfigResolver implements Resolve> { @@ -48,6 +46,7 @@ export class QueuesTableConfigResolver implements Resolve this.translate.instant('queue.delete-queue-text'); this.config.deleteEntitiesTitle = count => this.translate.instant('queue.delete-queues-title', {count}); this.config.deleteEntitiesContent = () => this.translate.instant('queue.delete-queues-text'); + + this.config.onEntityAction = action => this.onQueueAction(action); } resolve(route: ActivatedRouteSnapshot): Observable> { @@ -100,16 +101,28 @@ export class QueuesTableConfigResolver implements Resolve this.queueService.getTenantQueuesByServiceType(pageLink, this.queueType); this.config.loadEntity = id => this.queueService.getQueueById(id.id); - this.config.saveEntity = queue => this.queueService.saveQueue(this.addTopicForQueue(queue), this.queueType).pipe( + this.config.saveEntity = queue => this.queueService.saveQueue(queue, this.queueType).pipe( mergeMap((savedQueue) => this.queueService.getQueueById(savedQueue.id.id) )); this.config.deleteEntity = id => this.queueService.deleteQueue(id.id); this.config.deleteEnabled = (queue) => queue && queue.name !== 'Main'; + this.config.entitySelectionEnabled = (queue) => queue && queue.name !== 'Main'; + } + + onQueueAction(action: EntityAction): boolean { + switch (action.action) { + case 'open': + this.openQueue(action.event, action.entity); + return true; + } + return false; } - private addTopicForQueue(queue: QueueInfo): QueueInfo { - const modifiedQueue = Object.assign({}, queue); - modifiedQueue.topic = `tb_rule_engine.${queue.name}`; - return modifiedQueue; + private openQueue($event: Event, queue) { + if ($event) { + $event.stopPropagation(); + } + const url = this.router.createUrlTree(['settings', 'queues', queue.id.id]); + this.router.navigateByUrl(url); } } diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html index db9e899f1b..b991556b78 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html @@ -42,7 +42,7 @@ {{ translate.get('queue.no-queues-matching', - {entity: truncate.transform(searchText, true, 6, '...')}) | async }} + {queue: truncate.transform(searchText, true, 6, '...')}) | async }}
diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts index 28f40425ea..131e99d6e9 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts @@ -27,11 +27,11 @@ import { EntityType } from '@shared/models/entity-type.models'; import { BaseData } from '@shared/models/base-data'; import { EntityService } from '@core/http/entity.service'; import { TruncatePipe } from '@shared/pipe/truncate.pipe'; -import {QueueInfo, ServiceType} from "@shared/models/queue.models"; -import { QueueService } from "@core/http/queue.service"; -import { PageLink } from "@shared/models/page/page-link"; -import { Direction } from "@shared/models/page/sort-order"; -import { emptyPageData } from "@shared/models/page/page-data"; +import { QueueInfo, ServiceType } from '@shared/models/queue.models'; +import { QueueService } from '@core/http/queue.service'; +import { PageLink } from '@shared/models/page/page-link'; +import { Direction } from '@shared/models/page/sort-order'; +import { emptyPageData } from '@shared/models/page/page-data'; @Component({ selector: 'tb-queue-autocomplete', diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index c90af9df6a..df28c3bcfc 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -29,7 +29,7 @@ import * as _moment from 'moment'; import { AbstractControl, ValidationErrors } from '@angular/forms'; import { OtaPackageId } from '@shared/models/id/ota-package-id'; import { DashboardId } from '@shared/models/id/dashboard-id'; -import { QueueId } from "@shared/models/id/queue-id"; +import { QueueId } from '@shared/models/id/queue-id'; import { DataType } from '@shared/models/constants'; import { getDefaultProfileClientLwM2mSettingsConfig, diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index 9c97cdaa82..c92c2c43db 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -428,7 +428,8 @@ export const baseDetailsPageByEntityType = new Map([ [EntityType.EDGE, '/edgeInstances'], [EntityType.ENTITY_VIEW, '/entityViews'], [EntityType.TB_RESOURCE, '/settings/resources-library'], - [EntityType.OTA_PACKAGE, '/otaUpdates'] + [EntityType.OTA_PACKAGE, '/otaUpdates'], + [EntityType.QUEUE, '/settings/queues'] ]); export interface EntitySubtype { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 880778d6c4..5c73d7a017 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2719,13 +2719,15 @@ "partitions": "Partitions", "consumer-per-partition": "Consumer per partition", "consumer-per-partition-hint": "Enable separate consumer(s) per each partition", - "processing-timeout": "Processing timeout", + "processing-timeout": "Processing timeout, ms", "batch-size": "Batch size", "retries": "Retries (0 - unlimited)", "failure-percentage": "Failure Percentage", "pause-between-retries": "Pause between retries", "max-pause-between-retries": "Maximal pause between retries", - "delete": "Delete queue" + "delete": "Delete queue", + "copyId": "Copy queue Id", + "idCopiedMessage": "Queue Id has been copied to clipboard" }, "tenant": { "tenant": "Tenant", From acd7bd98d6466095e54498c5ab8790517f16d19b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 5 May 2022 11:06:36 +0200 Subject: [PATCH 21/58] fixed NP after changing tenant profile --- .../service/entity/tenant/DefaultTbTenantService.java | 1 + .../server/queue/discovery/HashPartitionService.java | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java index ca5bd08354..807cf6b1b1 100644 --- a/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java +++ b/application/src/main/java/org/thingsboard/server/service/entity/tenant/DefaultTbTenantService.java @@ -50,6 +50,7 @@ public class DefaultTbTenantService implements TbTenantService { TenantProfile oldTenantProfile = oldTenant != null ? tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, oldTenant.getTenantProfileId()) : null; TenantProfile newTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenant.getTenantProfileId()); + //TODO: send notifications before queue update tbQueueService.updateQueuesByTenants(Collections.singletonList(savedTenant.getTenantId()), newTenantProfile, oldTenantProfile); return savedTenant; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 246fac00af..c5d10d918f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -155,6 +155,8 @@ public class HashPartitionService implements PartitionService { myPartitions.remove(queueKey); partitionTopicsMap.remove(queueKey); partitionSizesMap.remove(queueKey); + //TODO: remove after merging tb entity services + removeTenant(tenantId); } @Override @@ -172,10 +174,10 @@ public class HashPartitionService implements PartitionService { //TODO: replace if we can notify CheckPoint rule nodes about queue changes if (queueRoutingInfo == null) { - log.warn("Queue was removed but still used in CheckPoint rule node. [{}][{}]", tenantId, entityId); + 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.warn("Tenant profile was changed but CheckPoint rule node still uses the queue from system level. [{}][{}]", tenantId, entityId); + 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); From 285f35b31b3e6ba8325f7619528a70114f4cbe2b Mon Sep 17 00:00:00 2001 From: fe-dev Date: Fri, 6 May 2022 12:28:11 +0300 Subject: [PATCH 22/58] UI: Fix trackby queues and add padding --- .../queue/tenant-profile-queues.component.ts | 8 +-- .../profile/tenant-profile.component.html | 60 ++++++++++--------- .../profile/tenant-profile.component.scss | 3 + 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts index a403f8e82e..7f4de4c68a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/queue/tenant-profile-queues.component.ts @@ -130,12 +130,8 @@ export class TenantProfileQueuesComponent implements ControlValueAccessor, Valid }); } - public trackByQueue(index: number, queueControl: AbstractControl): string { - if (queueControl) { - return queueControl.value.id; - } else { - return null; - } + public trackByQueue(index: number, queueControl: AbstractControl) { + return queueControl; } public removeQueue(index: number) { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html index 789ba8590a..fb20387608 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.html @@ -68,35 +68,37 @@
{{'tenant.isolated-tb-rule-engine-details' | translate}}
- - - - - {{'tenant-profile.queues-with-count' | translate: - {count: entityForm.get('profileData').get('queueConfiguration').value ? - entityForm.get('profileData').get('queueConfiguration').value.length : 0} }} - - - - - - - - - -
tenant-profile.profile-configuration
-
-
- - - - -
-
+
+ + + + + {{'tenant-profile.queues-with-count' | translate: + {count: entityForm.get('profileData').get('queueConfiguration').value ? + entityForm.get('profileData').get('queueConfiguration').value.length : 0} }} + + + + + + + + + +
tenant-profile.profile-configuration
+
+
+ + + + +
+
+
tenant-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss index e6e5d3b9cf..c76509e9e3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.scss @@ -35,4 +35,7 @@ width: fit-content; } } + .expansion-panel-block { + padding-bottom: 16px; + } } From 7dcb572dfd681d00f8e7ef2e5cc814aef135aa6f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 6 May 2022 21:18:48 +0200 Subject: [PATCH 23/58] added queue constraint processing --- .../server/dao/queue/BaseQueueService.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index c95635a439..a908ab8cdc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.queue; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.TenantProfile; @@ -62,7 +63,16 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ @Override public void deleteQueue(TenantId tenantId, QueueId queueId) { log.trace("Executing deleteQueue, queueId: [{}]", queueId); - queueDao.removeById(tenantId, queueId.getId()); + try { + queueDao.removeById(tenantId, queueId.getId()); + } catch (Exception t) { + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_queue_device_profile")) { + throw new DataValidationException("The queue referenced by the device profiles cannot be deleted!"); + } else { + throw t; + } + } } @Override From e241f73254a372e9733b80c7876458c2891c8365 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 6 May 2022 21:19:11 +0200 Subject: [PATCH 24/58] fixed queue updates --- .../thingsboard/server/queue/discovery/HashPartitionService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index c5d10d918f..92278f7b4a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -145,6 +145,7 @@ public class HashPartitionService implements PartitionService { queuesById.put(queue.getQueueId(), queue); partitionTopicsMap.put(queueKey, queueUpdateMsg.getQueueTopic()); partitionSizesMap.put(queueKey, queueUpdateMsg.getPartitions()); + myPartitions.remove(queueKey); } @Override From 3382ac480778e77b34e5f88648efe80cec79483e Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 9 May 2022 23:28:04 +0200 Subject: [PATCH 25/58] created Queue validator --- .../dao/device/DeviceProfileServiceImpl.java | 3 - .../server/dao/queue/BaseQueueService.java | 92 +------------ .../dao/service/validator/QueueValidator.java | 121 ++++++++++++++++++ 3 files changed, 124 insertions(+), 92 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index f33a78ebd1..05551f885b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -71,9 +71,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Autowired private CacheManager cacheManager; - @Autowired(required = false) - private QueueService queueService; - @Autowired private DataValidator deviceProfileValidator; diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index a908ab8cdc..a0254a4923 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.queue; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -26,10 +25,7 @@ import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.queue.ProcessingStrategy; 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.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; @@ -50,6 +46,9 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ @Autowired private TbTenantProfileCache tenantProfileCache; + @Autowired + private DataValidator queueValidator; + // @Autowired // private QueueStatsService queueStatsService; @@ -118,91 +117,6 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ tenantQueuesRemover.removeEntities(tenantId, tenantId); } - private DataValidator queueValidator = - new DataValidator<>() { - - @Override - protected void validateCreate(TenantId tenantId, Queue queue) { - if (queueDao.findQueueByTenantIdAndTopic(tenantId, queue.getTopic()) != null) { - throw new DataValidationException(String.format("Queue with topic: %s already exists!", queue.getTopic())); - } - if (queueDao.findQueueByTenantIdAndName(tenantId, queue.getName()) != null) { - throw new DataValidationException(String.format("Queue with name: %s already exists!", queue.getName())); - } - } - - @Override - protected void validateUpdate(TenantId tenantId, Queue queue) { - Queue foundQueue = queueDao.findById(tenantId, queue.getUuidId()); - if (queueDao.findById(tenantId, queue.getUuidId()) == null) { - throw new DataValidationException(String.format("Queue with id: %s does not exists!", queue.getId())); - } - if (!foundQueue.getName().equals(queue.getName())) { - throw new DataValidationException("Queue name can't be changed!"); - } - if (!foundQueue.getTopic().equals(queue.getTopic())) { - throw new DataValidationException("Queue topic can't be changed!"); - } - } - - @Override - protected void validateDataImpl(TenantId tenantId, Queue queue) { - if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { - TenantProfile tenantProfile = tenantProfileCache.get(tenantId); - - if (!tenantProfile.isIsolatedTbRuleEngine()) { - throw new DataValidationException("Tenant should be isolated!"); - } - } - - if (StringUtils.isEmpty(queue.getName())) { - throw new DataValidationException("Queue name should be specified!"); - } - if (StringUtils.isBlank(queue.getTopic())) { - throw new DataValidationException("Queue topic should be non empty and without spaces!"); - } - if (queue.getPollInterval() < 1) { - throw new DataValidationException("Queue poll interval should be more then 0!"); - } - if (queue.getPartitions() < 1) { - throw new DataValidationException("Queue partitions should be more then 0!"); - } - if (queue.getPackProcessingTimeout() < 1) { - throw new DataValidationException("Queue pack processing timeout should be more then 0!"); - } - - SubmitStrategy submitStrategy = queue.getSubmitStrategy(); - if (submitStrategy == null) { - throw new DataValidationException("Queue submit strategy can't be null!"); - } - if (submitStrategy.getType() == null) { - throw new DataValidationException("Queue submit strategy type can't be null!"); - } - if (submitStrategy.getType() == SubmitStrategyType.BATCH && submitStrategy.getBatchSize() < 1) { - throw new DataValidationException("Queue submit strategy batch size should be more then 0!"); - } - ProcessingStrategy processingStrategy = queue.getProcessingStrategy(); - if (processingStrategy == null) { - throw new DataValidationException("Queue processing strategy can't be null!"); - } - if (processingStrategy.getType() == null) { - throw new DataValidationException("Queue processing strategy type can't be null!"); - } - if (processingStrategy.getRetries() < 0) { - throw new DataValidationException("Queue processing strategy retries can't be less then 0!"); - } - if (processingStrategy.getFailurePercentage() < 0 || processingStrategy.getFailurePercentage() > 100) { - throw new DataValidationException("Queue processing strategy failure percentage should be in a range from 0 to 100!"); - } - if (processingStrategy.getPauseBetweenRetries() < 0) { - throw new DataValidationException("Queue processing strategy pause between retries can't be less then 0!"); - } - if (processingStrategy.getMaxPauseBetweenRetries() < processingStrategy.getPauseBetweenRetries()) { - throw new DataValidationException("Queue processing strategy MAX pause between retries can't be less then pause between retries!"); - } - } - }; - private PaginatedRemover tenantQueuesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java new file mode 100644 index 0000000000..a9f9838d1c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java @@ -0,0 +1,121 @@ +/** + * 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.dao.service.validator; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.data.queue.SubmitStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategyType; +import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.queue.QueueDao; +import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; + +@Component +public class QueueValidator extends DataValidator { + + @Autowired + private QueueDao queueDao; + + @Autowired + private TbTenantProfileCache tenantProfileCache; + + @Override + protected void validateCreate(TenantId tenantId, Queue queue) { + if (queueDao.findQueueByTenantIdAndTopic(tenantId, queue.getTopic()) != null) { + throw new DataValidationException(String.format("Queue with topic: %s already exists!", queue.getTopic())); + } + if (queueDao.findQueueByTenantIdAndName(tenantId, queue.getName()) != null) { + throw new DataValidationException(String.format("Queue with name: %s already exists!", queue.getName())); + } + } + + @Override + protected void validateUpdate(TenantId tenantId, Queue queue) { + Queue foundQueue = queueDao.findById(tenantId, queue.getUuidId()); + if (queueDao.findById(tenantId, queue.getUuidId()) == null) { + throw new DataValidationException(String.format("Queue with id: %s does not exists!", queue.getId())); + } + if (!foundQueue.getName().equals(queue.getName())) { + throw new DataValidationException("Queue name can't be changed!"); + } + if (!foundQueue.getTopic().equals(queue.getTopic())) { + throw new DataValidationException("Queue topic can't be changed!"); + } + } + + @Override + protected void validateDataImpl(TenantId tenantId, Queue queue) { + if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { + TenantProfile tenantProfile = tenantProfileCache.get(tenantId); + + if (!tenantProfile.isIsolatedTbRuleEngine()) { + throw new DataValidationException("Tenant should be isolated!"); + } + } + + if (StringUtils.isEmpty(queue.getName())) { + throw new DataValidationException("Queue name should be specified!"); + } + if (StringUtils.isBlank(queue.getTopic())) { + throw new DataValidationException("Queue topic should be non empty and without spaces!"); + } + if (queue.getPollInterval() < 1) { + throw new DataValidationException("Queue poll interval should be more then 0!"); + } + if (queue.getPartitions() < 1) { + throw new DataValidationException("Queue partitions should be more then 0!"); + } + if (queue.getPackProcessingTimeout() < 1) { + throw new DataValidationException("Queue pack processing timeout should be more then 0!"); + } + + SubmitStrategy submitStrategy = queue.getSubmitStrategy(); + if (submitStrategy == null) { + throw new DataValidationException("Queue submit strategy can't be null!"); + } + if (submitStrategy.getType() == null) { + throw new DataValidationException("Queue submit strategy type can't be null!"); + } + if (submitStrategy.getType() == SubmitStrategyType.BATCH && submitStrategy.getBatchSize() < 1) { + throw new DataValidationException("Queue submit strategy batch size should be more then 0!"); + } + ProcessingStrategy processingStrategy = queue.getProcessingStrategy(); + if (processingStrategy == null) { + throw new DataValidationException("Queue processing strategy can't be null!"); + } + if (processingStrategy.getType() == null) { + throw new DataValidationException("Queue processing strategy type can't be null!"); + } + if (processingStrategy.getRetries() < 0) { + throw new DataValidationException("Queue processing strategy retries can't be less then 0!"); + } + if (processingStrategy.getFailurePercentage() < 0 || processingStrategy.getFailurePercentage() > 100) { + throw new DataValidationException("Queue processing strategy failure percentage should be in a range from 0 to 100!"); + } + if (processingStrategy.getPauseBetweenRetries() < 0) { + throw new DataValidationException("Queue processing strategy pause between retries can't be less then 0!"); + } + if (processingStrategy.getMaxPauseBetweenRetries() < processingStrategy.getPauseBetweenRetries()) { + throw new DataValidationException("Queue processing strategy MAX pause between retries can't be less then pause between retries!"); + } + } +} From d5ef34cfb826ece55cc903ee6de30fc3a353d0bf Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 10 May 2022 19:44:58 +0200 Subject: [PATCH 26/58] added additional info to Queue --- .../thingsboard/server/common/data/queue/Queue.java | 9 +++++++-- .../thingsboard/server/dao/model/ModelConstants.java | 2 ++ .../thingsboard/server/dao/model/sql/QueueEntity.java | 10 ++++++++-- dao/src/main/resources/sql/schema-entities.sql | 3 ++- ui-ngx/src/app/shared/models/queue.models.ts | 1 + 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java index 90caa9c03f..f65609beae 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java @@ -16,15 +16,15 @@ package org.thingsboard.server.common.data.queue; import lombok.Data; -import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; @Data -public class Queue extends BaseData implements HasName, HasTenantId { +public class Queue extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId { private TenantId tenantId; private String name; private String topic; @@ -53,4 +53,9 @@ public class Queue extends BaseData implements HasName, HasTenantId { this.submitStrategy = queueConfiguration.getSubmitStrategy(); this.processingStrategy = queueConfiguration.getProcessingStrategy(); } + + @Override + public String getSearchText() { + return getName(); + } } \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index d122f712ca..8bdbed8e5c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -595,6 +595,8 @@ public class ModelConstants { public static final String QUEUE_SUBMIT_STRATEGY_PROPERTY = "submit_strategy"; public static final String QUEUE_PROCESSING_STRATEGY_PROPERTY = "processing_strategy"; public static final String QUEUE_COLUMN_FAMILY_NAME = "queue"; + public static final String QUEUE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; + protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, JSON_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java index fefe686c9e..ca7ab13c9b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/QueueEntity.java @@ -73,6 +73,10 @@ public class QueueEntity extends BaseSqlEntity { @Column(name = ModelConstants.QUEUE_PROCESSING_STRATEGY_PROPERTY) private JsonNode processingStrategy; + @Type(type = "json") + @Column(name = ModelConstants.QUEUE_ADDITIONAL_INFO_PROPERTY) + private JsonNode additionalInfo; + public QueueEntity() { } @@ -90,6 +94,7 @@ public class QueueEntity extends BaseSqlEntity { this.packProcessingTimeout = queue.getPackProcessingTimeout(); this.submitStrategy = mapper.valueToTree(queue.getSubmitStrategy()); this.processingStrategy = mapper.valueToTree(queue.getProcessingStrategy()); + this.additionalInfo = queue.getAdditionalInfo(); } @Override @@ -103,8 +108,9 @@ public class QueueEntity extends BaseSqlEntity { queue.setPartitions(partitions); queue.setConsumerPerPartition(consumerPerPartition); queue.setPackProcessingTimeout(packProcessingTimeout); - queue.setSubmitStrategy(mapper.convertValue(this.submitStrategy, SubmitStrategy.class)); - queue.setProcessingStrategy(mapper.convertValue(this.processingStrategy, ProcessingStrategy.class)); + queue.setSubmitStrategy(mapper.convertValue(submitStrategy, SubmitStrategy.class)); + queue.setProcessingStrategy(mapper.convertValue(processingStrategy, ProcessingStrategy.class)); + queue.setAdditionalInfo(additionalInfo); return queue; } } \ No newline at end of file diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index d71e2fb4dd..2affd12547 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -226,7 +226,8 @@ CREATE TABLE IF NOT EXISTS queue( consumer_per_partition boolean, pack_processing_timeout bigint, submit_strategy varchar(255), - processing_strategy varchar(255) + processing_strategy varchar(255), + additional_info varchar ); CREATE TABLE IF NOT EXISTS device_profile ( diff --git a/ui-ngx/src/app/shared/models/queue.models.ts b/ui-ngx/src/app/shared/models/queue.models.ts index 3224d7dc23..2b4891171b 100644 --- a/ui-ngx/src/app/shared/models/queue.models.ts +++ b/ui-ngx/src/app/shared/models/queue.models.ts @@ -61,4 +61,5 @@ export interface QueueInfo extends BaseData { }; tenantId?: TenantId; topic: string; + additionalInfo?: any; } From 7d7d48f42ebd923dadb689f4e2a64fa87acbf358 Mon Sep 17 00:00:00 2001 From: fe-dev Date: Wed, 11 May 2022 14:19:00 +0300 Subject: [PATCH 27/58] UI: delete queue-type-list and add to autocomplete description --- ui-ngx/src/app/core/http/queue.service.ts | 5 - ui-ngx/src/app/modules/common/modules-map.ts | 4 +- .../queue/queue-form.component.html | 4 + .../queue/queue-form.component.scss | 2 + .../components/queue/queue-form.component.ts | 5 +- .../queue/queue-autocomplete.component.html | 1 + .../queue/queue-autocomplete.component.ts | 5 + .../queue/queue-type-list.component.html | 49 ----- .../queue/queue-type-list.component.ts | 199 ------------------ ui-ngx/src/app/shared/models/queue.models.ts | 4 +- ui-ngx/src/app/shared/shared.module.ts | 3 - .../assets/locale/locale.constant-en_US.json | 4 +- 12 files changed, 24 insertions(+), 261 deletions(-) delete mode 100644 ui-ngx/src/app/shared/components/queue/queue-type-list.component.html delete mode 100644 ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts diff --git a/ui-ngx/src/app/core/http/queue.service.ts b/ui-ngx/src/app/core/http/queue.service.ts index a5967eef97..f5dff9b4d5 100644 --- a/ui-ngx/src/app/core/http/queue.service.ts +++ b/ui-ngx/src/app/core/http/queue.service.ts @@ -31,11 +31,6 @@ export class QueueService { private http: HttpClient ) { } - public getTenantQueuesNamesByServiceType(serviceType: ServiceType, config?: RequestConfig): Observable> { - return this.http.get>(`/api/queues?serviceType=${serviceType}`, - defaultHttpOptionsFromConfig(config)); - } - public getQueueById(queueId: string, config?: RequestConfig): Observable { return this.http.get(`/api/queues/${queueId}`, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index a1fca3f603..8be36ec33d 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -135,7 +135,7 @@ import * as EntitySelectComponent from '@shared/components/entity/entity-select. import * as EntityKeysListComponent from '@shared/components/entity/entity-keys-list.component'; import * as EntityListSelectComponent from '@shared/components/entity/entity-list-select.component'; import * as EntityTypeListComponent from '@shared/components/entity/entity-type-list.component'; -import * as QueueTypeListComponent from '@shared/components/queue/queue-type-list.component'; +import * as QueueAutocompleteComponent from '@shared/components/queue/queue-autocomplete.component'; import * as RelationTypeAutocompleteComponent from '@shared/components/relation/relation-type-autocomplete.component'; import * as SocialSharePanelComponent from '@shared/components/socialshare-panel.component'; import * as JsonObjectEditComponent from '@shared/components/json-object-edit.component'; @@ -419,7 +419,7 @@ class ModulesMap implements IModulesMap { '@shared/components/entity/entity-keys-list.component': EntityKeysListComponent, '@shared/components/entity/entity-list-select.component': EntityListSelectComponent, '@shared/components/entity/entity-type-list.component': EntityTypeListComponent, - '@shared/components/queue/queue-type-list.component': QueueTypeListComponent, + '@shared/components/queue/queue-autocomplete.component': QueueAutocompleteComponent, '@shared/components/relation/relation-type-autocomplete.component': RelationTypeAutocompleteComponent, '@shared/components/socialshare-panel.component': SocialSharePanelComponent, '@shared/components/json-object-edit.component': JsonObjectEditComponent, diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html index 9ea9720b7b..e13faf0f43 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html @@ -168,4 +168,8 @@
+ + queue.description + + diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss index d20faee49c..c42c4d714d 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss @@ -15,6 +15,8 @@ */ :host ::ng-deep { .queue-strategy { + padding-bottom: 16px; + .mat-expansion-panel-body { padding-bottom: 0 !important; } diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts index c3d4b1273a..38552bff25 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts @@ -109,7 +109,10 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, Validat pauseBetweenRetries: [3, [Validators.min(1), Validators.required]], maxPauseBetweenRetries: [3, [Validators.min(1), Validators.required]], }), - topic: [''] + topic: [''], + additionalInfo: this.fb.group({ + description: [''] + }) }); this.queueFormGroup.valueChanges.subscribe(() => { this.updateModel(); diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html index b991556b78..471d191b61 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.html @@ -33,6 +33,7 @@ [displayWith]="displayQueueFn"> + {{getDescription(queue)}}
diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts index 131e99d6e9..0caa487d66 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts @@ -205,6 +205,11 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit ); } + getDescription(value) { + return value.additionalInfo?.description ? value.additionalInfo.description : + `Submit Strategy: ${value.submitStrategy.type}, Processing Strategy: ${value.processingStrategy.type}`; + } + clear() { this.selectQueueFormGroup.get('queueId').patchValue('', {emitEvent: true}); setTimeout(() => { diff --git a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html deleted file mode 100644 index 29de0f2f12..0000000000 --- a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.html +++ /dev/null @@ -1,49 +0,0 @@ - - - {{ 'queue.queue-name' | translate }} - - - - - - - - - {{ translate.get('queue.no-queues-matching', {queue: searchText}) | async }} - - - - - {{ 'queue.name-required' | translate }} - - device-profile.select-queue-hint - diff --git a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts b/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts deleted file mode 100644 index 28a3d94e9e..0000000000 --- a/ui-ngx/src/app/shared/components/queue/queue-type-list.component.ts +++ /dev/null @@ -1,199 +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. -/// - -import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Observable, of } from 'rxjs'; -import { - catchError, - debounceTime, - distinctUntilChanged, - map, - publishReplay, - refCount, - switchMap, - tap -} from 'rxjs/operators'; -import { Store } from '@ngrx/store'; -import { AppState } from '@app/core/core.state'; -import { TranslateService } from '@ngx-translate/core'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { QueueService } from '@core/http/queue.service'; -import { ServiceType } from '@shared/models/queue.models'; - -interface Queue { - queueName: string; -} - -@Component({ - selector: 'tb-queue-type-list', - templateUrl: './queue-type-list.component.html', - styleUrls: [], - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => QueueTypeListComponent), - multi: true - }] -}) -export class QueueTypeListComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnDestroy { - - queueFormGroup: FormGroup; - - modelValue: Queue | null; - - private requiredValue: boolean; - get required(): boolean { - return this.requiredValue; - } - @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } - - @Input() - disabled: boolean; - - @Input() - queueType: ServiceType; - - @ViewChild('queueInput', {static: true}) queueInput: ElementRef; - - filteredQueues: Observable>; - - queues: Observable>; - - searchText = ''; - - private dirty = false; - - private propagateChange = (v: any) => { }; - - constructor(private store: Store, - public translate: TranslateService, - private queueService: QueueService, - private fb: FormBuilder) { - this.queueFormGroup = this.fb.group({ - queue: [null] - }); - } - - registerOnChange(fn: any): void { - this.propagateChange = fn; - } - - registerOnTouched(fn: any): void { - } - - ngOnInit() { - this.filteredQueues = this.queueFormGroup.get('queue').valueChanges - .pipe( - debounceTime(150), - distinctUntilChanged(), - tap(value => { - let modelValue; - if (typeof value === 'string' || !value) { - modelValue = null; - } else { - modelValue = value; - } - this.updateView(modelValue); - }), - map(value => value ? (typeof value === 'string' ? value : value.queueName) : ''), - switchMap(queue => this.fetchQueues(queue) ) - ); - } - - ngAfterViewInit(): void { - } - - ngOnDestroy(): void { - } - - setDisabledState(isDisabled: boolean): void { - this.disabled = isDisabled; - if (this.disabled) { - this.queueFormGroup.disable({emitEvent: false}); - } else { - this.queueFormGroup.enable({emitEvent: false}); - } - } - - writeValue(value: string | null): void { - this.searchText = ''; - this.modelValue = value ? { queueName: value } : null; - this.queueFormGroup.get('queue').patchValue(this.modelValue, {emitEvent: false}); - this.dirty = true; - } - - onFocus() { - if (this.dirty) { - this.queueFormGroup.get('queue').updateValueAndValidity({onlySelf: true, emitEvent: true}); - this.dirty = false; - } - } - - updateView(value: Queue | null) { - if (this.modelValue !== value) { - this.modelValue = value; - this.propagateChange(this.modelValue ? this.modelValue.queueName : null); - } - } - - displayQueueFn(queue?: Queue): string | undefined { - return queue ? queue.queueName : undefined; - } - - fetchQueues(searchText?: string): Observable> { - this.searchText = searchText; - return this.getQueues().pipe( - catchError(() => of([] as Array)), - map(queues => { - const result = queues.filter( queue => { - return searchText ? queue.queueName.toUpperCase().startsWith(searchText.toUpperCase()) : true; - }); - if (result.length) { - result.sort((q1, q2) => q1.queueName.localeCompare(q2.queueName)); - } - return result; - }) - ); - } - - getQueues(): Observable> { - if (!this.queues) { - this.queues = this.queueService. - getTenantQueuesNamesByServiceType(this.queueType, {ignoreLoading: true}).pipe( - map((queues) => { - return queues.map((queueName) => { - return { queueName }; - }); - }), - publishReplay(1), - refCount() - ); - } - return this.queues; - } - - clear() { - this.queueFormGroup.get('queue').patchValue(null, {emitEvent: true}); - setTimeout(() => { - this.queueInput.nativeElement.blur(); - this.queueInput.nativeElement.focus(); - }, 0); - } - -} diff --git a/ui-ngx/src/app/shared/models/queue.models.ts b/ui-ngx/src/app/shared/models/queue.models.ts index 2b4891171b..86bd99a19d 100644 --- a/ui-ngx/src/app/shared/models/queue.models.ts +++ b/ui-ngx/src/app/shared/models/queue.models.ts @@ -61,5 +61,7 @@ export interface QueueInfo extends BaseData { }; tenantId?: TenantId; topic: string; - additionalInfo?: any; + additionalInfo: { + description?: string; + }; } diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 7a2b0fb28b..6c28cf42ab 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -136,7 +136,6 @@ import { JsonObjectEditDialogComponent } from '@shared/components/dialog/json-ob import { HistorySelectorComponent } from '@shared/components/time/history-selector/history-selector.component'; import { EntityGatewaySelectComponent } from '@shared/components/entity/entity-gateway-select.component'; import { DndModule } from 'ngx-drag-drop'; -import { QueueTypeListComponent } from '@shared/components/queue/queue-type-list.component'; import { QueueAutocompleteComponent } from '@shared/components/queue/queue-autocomplete.component'; import { ContactComponent } from '@shared/components/contact.component'; import { TimezoneSelectComponent } from '@shared/components/time/timezone-select.component'; @@ -232,7 +231,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) EntityKeysListComponent, EntityListSelectComponent, EntityTypeListComponent, - QueueTypeListComponent, QueueAutocompleteComponent, RelationTypeAutocompleteComponent, SocialSharePanelComponent, @@ -381,7 +379,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) EntityKeysListComponent, EntityListSelectComponent, EntityTypeListComponent, - QueueTypeListComponent, QueueAutocompleteComponent, RelationTypeAutocompleteComponent, SocialSharePanelComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 2588a4d410..9fe5d0fbed 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2757,6 +2757,7 @@ "select-name": "Select queue name", "name": "Name", "name-required": "Queue name is required!", + "queue-required": "Queue is required!", "topic-required": "Queue topic is required!", "poll-interval-required": "Poll interval is required!", "poll-interval-min-value": "Poll interval value can't be less then 1", @@ -2801,7 +2802,8 @@ "max-pause-between-retries": "Maximal pause between retries", "delete": "Delete queue", "copyId": "Copy queue Id", - "idCopiedMessage": "Queue Id has been copied to clipboard" + "idCopiedMessage": "Queue Id has been copied to clipboard", + "description": "Description" }, "tenant": { "tenant": "Tenant", From bdf1807223017c1b817ba76585e58264c8c7c79d Mon Sep 17 00:00:00 2001 From: fe-dev Date: Wed, 11 May 2022 14:20:37 +0300 Subject: [PATCH 28/58] UI: Update rulenode core --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 11b35b2a24..f7ead71ec3 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/material/form-field","@angular/material/checkbox","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/input","@angular/common","@angular/platform-browser","@angular/material/select","@angular/material/core","@angular/material/expansion","@shared/components/button/toggle-password.component","@shared/components/file-input.component","@shared/components/queue/queue-type-list.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@angular/cdk/keycodes","@angular/material/chips","@angular/material/icon","@angular/flex-layout/extended","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","rxjs/operators","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@home/components/public-api","@shared/components/relation/relation-type-autocomplete.component","@shared/components/entity/entity-subtype-list.component","@home/components/relation/relation-filters.component","rxjs","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,o,r,a,n,l,i,s,m,u,p,d,f,c,g,x,y,b,h,C,F,L,v,I,N,T,q,k,M,S,A,G,D,V,E,P,R,w,O,H,U,K,B,j,z,_,Q,$,W,Y,J,Z,X,ee,te,oe,re,ae,ne,le,ie,se,me,ue,pe,de,fe,ce,ge,xe,ye,be,he,Ce,Fe,Le,ve,Ie;return{setters:[function(e){t=e,o=e.Component,r=e.Pipe,a=e.ViewChild,n=e.forwardRef,l=e.Input,i=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.AlarmSeverity,f=e.alarmSeverityTranslations,c=e.EntitySearchDirection,g=e.entitySearchDirectionTranslations,x=e.EntityType,y=e.PageComponent,b=e.MessageType,h=e.messageTypeNames,C=e,F=e.SharedModule,L=e.AggregationType,v=e.aggregationTranslations,I=e.alarmStatusTranslations,N=e.AlarmStatus},function(e){T=e},function(e){q=e,k=e.Validators,M=e.NgControl,S=e.NG_VALUE_ACCESSOR,A=e.NG_VALIDATORS,G=e.FormControl},function(e){D=e},function(e){V=e},function(e){E=e},function(e){P=e},function(e){R=e},function(e){w=e,O=e.CommonModule},function(e){H=e},function(e){U=e},function(e){K=e},function(e){B=e},function(e){j=e},function(e){z=e},function(e){_=e},function(e){Q=e,$=e.isDefinedAndNotNull,W=e.isNotEmptyStr},function(e){Y=e},function(e){J=e},function(e){Z=e.ENTER,X=e.COMMA,ee=e.SEMICOLON},function(e){te=e},function(e){oe=e},function(e){re=e},function(e){ae=e},function(e){ne=e},function(e){le=e.coerceBooleanProperty},function(e){ie=e},function(e){se=e},function(e){me=e.distinctUntilChanged,ue=e.startWith,pe=e.map,de=e.mergeMap,fe=e.share},function(e){ce=e},function(e){ge=e},function(e){xe=e.HomeComponentsModule},function(e){ye=e},function(e){be=e},function(e){he=e},function(e){Ce=e.of},function(e){Fe=e},function(e){Le=e},function(e){ve=e},function(e){Ie=e}],execute:function(){class Ne extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Ne),Ne.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ne,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ne.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ne,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ne,decorators:[{type:o,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Te{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Te),Te.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,deps:[{token:H.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Te.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:H.DomSanitizer}]}});class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[k.required,k.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[k.required,k.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",qe),qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qe,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qe,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qe,decorators:[{type:o,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ke extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]],notifyDevice:[!e||e.notifyDevice,[]]})}}var Me;e("AttributesConfigComponent",ke),ke.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ke,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ke.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ke,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ke,decorators:[{type:o,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(Me||(Me={}));const Se=new Map([[Me.CUSTOMER,"tb.rulenode.originator-customer"],[Me.TENANT,"tb.rulenode.originator-tenant"],[Me.RELATED,"tb.rulenode.originator-related"],[Me.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);var Ae;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Ae||(Ae={}));const Ge=new Map([[Ae.CIRCLE,"tb.rulenode.perimeter-circle"],[Ae.POLYGON,"tb.rulenode.perimeter-polygon"]]);var De;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(De||(De={}));const Ve=new Map([[De.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[De.SECONDS,"tb.rulenode.time-unit-seconds"],[De.MINUTES,"tb.rulenode.time-unit-minutes"],[De.HOURS,"tb.rulenode.time-unit-hours"],[De.DAYS,"tb.rulenode.time-unit-days"]]);var Ee;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(Ee||(Ee={}));const Pe=new Map([[Ee.METER,"tb.rulenode.range-unit-meter"],[Ee.KILOMETER,"tb.rulenode.range-unit-kilometer"],[Ee.FOOT,"tb.rulenode.range-unit-foot"],[Ee.MILE,"tb.rulenode.range-unit-mile"],[Ee.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Re;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Re||(Re={}));const we=new Map([[Re.TITLE,"tb.rulenode.entity-details-title"],[Re.COUNTRY,"tb.rulenode.entity-details-country"],[Re.STATE,"tb.rulenode.entity-details-state"],[Re.CITY,"tb.rulenode.entity-details-city"],[Re.ZIP,"tb.rulenode.entity-details-zip"],[Re.ADDRESS,"tb.rulenode.entity-details-address"],[Re.ADDRESS2,"tb.rulenode.entity-details-address2"],[Re.PHONE,"tb.rulenode.entity-details-phone"],[Re.EMAIL,"tb.rulenode.entity-details-email"],[Re.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Oe,He,Ue;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Oe||(Oe={})),function(e){e.ASC="ASC",e.DESC="DESC"}(He||(He={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Ue||(Ue={}));const Ke=new Map([[Ue.STANDARD,"tb.rulenode.sqs-queue-standard"],[Ue.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Be=["anonymous","basic","cert.PEM"],je=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),ze=["sas","cert.PEM"],_e=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Qe;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Qe||(Qe={}));const $e=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],We=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=ze,this.azureIotHubCredentialsTypeTranslationsMap=_e}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[k.required,k.min(1),k.max(200)]],clientId:[e?e.clientId:null,[k.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[k.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([k.required]);break;case"cert.PEM":t.get("privateKey").setValidators([k.required]),t.get("privateKeyFileName").setValidators([k.required]),t.get("cert").setValidators([k.required]),t.get("certFileName").setValidators([k.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ye,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ye,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:B.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:q.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:w.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ye,decorators:[{type:o,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[k.required]]})}}e("CheckPointConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Je,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Je,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:_.QueueTypeListComponent,selector:"tb-queue-type-list",inputs:["required","disabled","queueType"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Je,decorators:[{type:o,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ze extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[k.required]],alarmType:[e?e.alarmType:null,[k.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ze,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ze,decorators:[{type:o,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Xe extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[k.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([k.required]),this.createAlarmConfigForm.get("severity").setValidators([k.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;e&&!t||this.jsFuncComponent.validateOnSubmit()}}e("CreateAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xe,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xe,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xe,decorators:[{type:o,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[k.required]],entityType:[e?e.entityType:null,[k.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[k.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[k.required,k.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([k.required,k.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([k.required,k.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:et,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:et,decorators:[{type:o,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[k.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[k.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[k.required,k.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([k.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([k.required,k.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:tt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:tt,decorators:[{type:o,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,k.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,k.required]})}}e("DeviceProfileConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ot,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ot,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ot,decorators:[{type:o,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class rt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[k.required,k.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[k.required,k.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[k.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:rt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:ne.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:rt,decorators:[{type:o,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class at extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ae,this.perimeterTypes=Object.keys(Ae),this.perimeterTypeTranslationMap=Ge,this.rangeUnits=Object.keys(Ee),this.rangeUnitTranslationMap=Pe,this.timeUnits=Object.keys(De),this.timeUnitsTranslationMap=Ve}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[k.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[k.required]],perimeterType:[e?e.perimeterType:null,[k.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[k.required,k.min(1),k.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[k.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[k.required,k.min(1),k.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[k.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([k.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ae.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([k.required,k.min(-90),k.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([k.required,k.min(-180),k.max(180)]),this.geoActionConfigForm.get("range").setValidators([k.required,k.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([k.required])),t||o!==Ae.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([k.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",at),at.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:at,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),at.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:at,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:at,decorators:[{type:o,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class nt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.ngControl=this.injector.get(M),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[k.required]],value:[e[o],[k.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[k.required]],value:["",[k.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:nt,deps:[{token:T.Store},{token:P.TranslateService},{token:t.Injector},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:nt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:S,useExisting:n((()=>nt)),multi:!0},{provide:A,useExisting:n((()=>nt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0;align-self:baseline}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:q.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:se.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:nt,decorators:[{type:o,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:S,useExisting:n((()=>nt)),multi:!0},{provide:A,useExisting:n((()=>nt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:t.Injector},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],required:[{type:l}]}});class lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=$e,this.ToByteStandartCharsetTypeTranslationMap=We}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],bootstrapServers:[e?e.bootstrapServers:null,[k.required]],retries:[e?e.retries:null,[k.min(0)]],batchSize:[e?e.batchSize:null,[k.min(0)]],linger:[e?e.linger:null,[k.min(0)]],bufferMemory:[e?e.bufferMemory:null,[k.min(0)]],acks:[e?e.acks:null,[k.required]],keySerializer:[e?e.keySerializer:null,[k.required]],valueSerializer:[e?e.valueSerializer:null,[k.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([k.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",lt),lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:lt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:lt,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:lt,decorators:[{type:o,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class it extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",it),it.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:it,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),it.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:it,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:it,decorators:[{type:o,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class st extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Be,this.credentialsTypeTranslationsMap=je,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[k.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(me()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){$(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([k.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[k.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(k.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",st),st.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:st,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),st.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:st,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:S,useExisting:n((()=>st)),multi:!0},{provide:A,useExisting:n((()=>st)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:B.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:D.MatLabel,selector:"mat-label"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:w.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:w.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:st,decorators:[{type:o,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>st)),multi:!0},{provide:A,useExisting:n((()=>st)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{required:[{type:l}],disableCertPemCredentials:[{type:l}],passwordFieldRquired:[{type:l}]}});class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[k.required,k.min(1),k.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&W(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{W(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",mt),mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:mt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:mt,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:st,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:mt,decorators:[{type:o,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[k.required,k.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[k.required]]})}}e("MsgCountConfigComponent",ut),ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ut,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ut,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ut,decorators:[{type:o,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[k.required,k.min(1),k.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([k.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([k.required,k.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",pt),pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:pt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:pt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:pt,decorators:[{type:o,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[k.required]],topicName:[e?e.topicName:null,[k.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[k.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[k.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",dt),dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:dt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:dt,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:dt,decorators:[{type:o,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]]})}}e("PushToCloudConfigComponent",ft),ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ft,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ft,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ft,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]]})}}e("PushToEdgeConfigComponent",ct),ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ct,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ct,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ct,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[k.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[k.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",gt),gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:gt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:gt,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:gt,decorators:[{type:o,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Qe)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[k.required]],requestMethod:[e?e.requestMethod:null,[k.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[k.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[k.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[k.required,k.min(1),k.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([k.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([k.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",xt),xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:xt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:xt,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:st,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:xt,decorators:[{type:o,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",yt),yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:yt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:yt,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[k.required,k.min(0)]]})}}e("RpcRequestConfigComponent",bt),bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:bt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:bt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:bt,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[k.required,k.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[k.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",ht),ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ht,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ht,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ht,decorators:[{type:o,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([k.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([k.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([k.required,k.min(1),k.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([k.required,k.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[k.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[k.required,k.min(1),k.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Ct),Ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ct,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ct,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ce.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ct,decorators:[{type:o,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[k.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[k.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([k.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Ft),Ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ft,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ft,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:ge.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ft,decorators:[{type:o,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[k.required]],accessKeyId:[e?e.accessKeyId:null,[k.required]],secretAccessKey:[e?e.secretAccessKey:null,[k.required]],region:[e?e.region:null,[k.required]]})}}e("SnsConfigComponent",Lt),Lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Lt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Lt,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Lt,decorators:[{type:o,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Ue,this.sqsQueueTypes=Object.keys(Ue),this.sqsQueueTypeTranslationsMap=Ke}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[k.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[k.required]],delaySeconds:[e?e.delaySeconds:null,[k.min(0),k.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[k.required]],secretAccessKey:[e?e.secretAccessKey:null,[k.required]],region:[e?e.region:null,[k.required]]})}}e("SqsConfigComponent",vt),vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:vt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:vt,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:vt,decorators:[{type:o,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class It extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[k.required,k.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",It),It.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:It,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),It.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:It,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:It,decorators:[{type:o,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[k.required,k.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[k.required,k.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Nt),Nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Nt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Nt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Nt,decorators:[{type:o,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Tt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[k.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[k.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Tt),Tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Tt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Tt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>Tt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ye.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:be.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Tt,decorators:[{type:o,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>Tt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class qt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[k.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",qt),qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:he.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qt,decorators:[{type:o,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>qt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class kt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[Z,X,ee],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchMessageTypes(e))),fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ce(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",kt),kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:kt,deps:[{token:T.Store},{token:P.TranslateService},{token:C.TruncatePipe},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:kt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:S,useExisting:n((()=>kt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:kt,decorators:[{type:o,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>kt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:C.TruncatePipe},{type:q.FormBuilder}]},propDecorators:{required:[{type:l}],label:[{type:l}],placeholder:[{type:l}],disabled:[{type:l}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class Mt{}e("RulenodeCoreConfigCommonModule",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Mt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,declarations:[nt,Tt,qt,kt,st,Te],imports:[O,F,xe],exports:[nt,Tt,qt,kt,st,Te]}),Mt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,imports:[[O,F,xe]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,decorators:[{type:i,args:[{declarations:[nt,Tt,qt,kt,st,Te],imports:[O,F,xe],exports:[nt,Tt,qt,kt,st,Te]}]}]});class St{}e("RuleNodeCoreConfigActionModule",St),St.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,deps:[],target:t.ɵɵFactoryTarget.NgModule}),St.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,declarations:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft],imports:[O,F,xe,Mt],exports:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft]}),St.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,imports:[[O,F,xe,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,decorators:[{type:i,args:[{declarations:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft],imports:[O,F,xe,Mt],exports:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft]}]}]});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[k.required]],outputValueKey:[e?e.outputValueKey:null,[k.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[k.min(0),k.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([k.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:At,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:At,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:At,decorators:[{type:o,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("CustomerAttributesConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Gt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Gt,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Gt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[k.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("DeviceAttributesConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Dt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Dt,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:Tt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Dt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Vt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=we,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Re))this.entityDetailsList.push(Re[e]);this.detailsFormControl=new G(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchEntityDetails(e))),fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[k.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(we.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(this.entityDetailsList.filter((t=>this.translate.instant(we.get(Re[t])).toUpperCase().includes(e))))}return Ce(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Vt,deps:[{token:T.Store},{token:P.TranslateService},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Vt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Vt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:q.FormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=v,this.fetchMode=Oe,this.fetchModes=Object.keys(Oe),this.samplingOrders=Object.keys(He),this.timeUnits=Object.values(De),this.timeUnitsTranslationMap=Ve}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[k.required]],fetchMode:[e?e.fetchMode:null,[k.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Oe.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([k.required,k.min(2),k.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([k.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([k.required,k.min(1),k.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([k.required,k.min(1),k.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Et,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Et,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Et,decorators:[{type:o,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("OriginatorAttributesConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Pt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Pt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Pt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[k.required]]})}}e("OriginatorFieldsConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Rt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Rt,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',components:[{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Rt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[k.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("RelatedAttributesConfigComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:wt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:wt,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:wt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("TenantAttributesConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ot,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ot,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ot,decorators:[{type:o,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ht{}e("RulenodeCoreConfigEnrichmentModule",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ht.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,declarations:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At],imports:[O,F,Mt],exports:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At]}),Ht.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,decorators:[{type:i,args:[{declarations:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At],imports:[O,F,Mt],exports:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At]}]}]});class Ut extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=I,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(N))this.alarmStatusList.push(N[e]);this.statusFormControl=new G(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchAlarmStatus(e))),fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[k.required]]})}displayStatus(e){return e?this.translate.instant(I.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(t.filter((t=>this.translate.instant(I.get(N[t])).toUpperCase().includes(e))))}return Ce(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ut,deps:[{token:T.Store},{token:P.TranslateService},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ut,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ut,decorators:[{type:o,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:q.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Kt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Kt,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Kt,decorators:[{type:o,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[k.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[k.required]:[]],relationType:[e?e.relationType:null,[k.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[k.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[k.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Bt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Bt,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:ve.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:ye.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Bt,decorators:[{type:o,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ae,this.perimeterTypes=Object.keys(Ae),this.perimeterTypeTranslationMap=Ge,this.rangeUnits=Object.keys(Ee),this.rangeUnitTranslationMap=Pe}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[k.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[k.required]],perimeterType:[e?e.perimeterType:null,[k.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([k.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ae.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([k.required,k.min(-90),k.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([k.required,k.min(-180),k.max(180)]),this.geoFilterConfigForm.get("range").setValidators([k.required,k.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([k.required])),t||o!==Ae.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([k.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:jt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:jt,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:jt,decorators:[{type:o,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[k.required]]})}}e("MessageTypeConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:zt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:zt,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',components:[{type:kt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:zt,decorators:[{type:o,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[k.required]]})}}e("OriginatorTypeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:_t,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:_t,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Ie.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:_t,decorators:[{type:o,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Qt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Qt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Qt,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Qt,decorators:[{type:o,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class $t extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:$t,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$t,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:$t,decorators:[{type:o,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Wt{}e("RuleNodeCoreConfigFilterModule",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,declarations:[Kt,Bt,jt,zt,_t,Qt,$t,Ut],imports:[O,F,Mt],exports:[Kt,Bt,jt,zt,_t,Qt,$t,Ut]}),Wt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,decorators:[{type:i,args:[{declarations:[Kt,Bt,jt,zt,_t,Qt,$t,Ut],imports:[O,F,Mt],exports:[Kt,Bt,jt,zt,_t,Qt,$t,Ut]}]}]});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Me,this.originatorSources=Object.keys(Me),this.originatorSourceTranslationMap=Se}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[k.required]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===Me.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([k.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Yt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Yt,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:qt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Yt,decorators:[{type:o,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Jt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Jt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Jt,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Jt,decorators:[{type:o,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[k.required]],toTemplate:[e?e.toTemplate:null,[k.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[k.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[k.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ue([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(k.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Zt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Zt,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Zt,decorators:[{type:o,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Xt{}e("RulenodeCoreConfigTransformModule",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,declarations:[Yt,Jt,Zt],imports:[O,F,Mt],exports:[Yt,Jt,Zt]}),Xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,decorators:[{type:i,args:[{declarations:[Yt,Jt,Zt],imports:[O,F,Mt],exports:[Yt,Jt,Zt]}]}]});class eo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[k.required]]})}}e("RuleChainInputComponent",eo),eo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:eo,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),eo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:eo,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:ve.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:eo,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class to extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",to),to.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:to,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),to.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:to,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:to,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class oo{}e("RuleNodeCoreConfigFlowModule",oo),oo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,deps:[],target:t.ɵɵFactoryTarget.NgModule}),oo.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,declarations:[eo,to],imports:[O,F,Mt],exports:[eo,to]}),oo.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,decorators:[{type:i,args:[{declarations:[eo,to],imports:[O,F,Mt],exports:[eo,to]}]}]});class ro{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",ro),ro.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,deps:[{token:P.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),ro.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,declarations:[Ne],imports:[O,F],exports:[St,Wt,Ht,Xt,oo,Ne]}),ro.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,imports:[[O,F],St,Wt,Ht,Xt,oo]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,decorators:[{type:i,args:[{declarations:[Ne],imports:[O,F],exports:[St,Wt,Ht,Xt,oo,Ne]}]}],ctorParameters:function(){return[{type:P.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/material/form-field","@angular/material/checkbox","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/input","@angular/common","@angular/platform-browser","@angular/material/select","@angular/material/core","@angular/material/expansion","@shared/components/button/toggle-password.component","@shared/components/file-input.component","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@angular/cdk/keycodes","@angular/material/chips","@angular/material/icon","@angular/flex-layout/extended","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","rxjs/operators","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@home/components/public-api","@shared/components/relation/relation-type-autocomplete.component","@shared/components/entity/entity-subtype-list.component","@home/components/relation/relation-filters.component","rxjs","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,o,r,a,n,l,i,s,m,u,p,d,f,c,g,x,y,b,h,C,F,L,v,I,N,T,q,k,M,S,A,G,D,V,E,P,R,w,O,H,U,K,B,j,z,_,Q,$,W,Y,J,Z,X,ee,te,oe,re,ae,ne,le,ie,se,me,ue,pe,de,fe,ce,ge,xe,ye,be,he,Ce,Fe,Le,ve,Ie;return{setters:[function(e){t=e,o=e.Component,r=e.Pipe,a=e.ViewChild,n=e.forwardRef,l=e.Input,i=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.AlarmSeverity,f=e.alarmSeverityTranslations,c=e.EntitySearchDirection,g=e.entitySearchDirectionTranslations,x=e.EntityType,y=e.PageComponent,b=e.MessageType,h=e.messageTypeNames,C=e,F=e.SharedModule,L=e.AggregationType,v=e.aggregationTranslations,I=e.alarmStatusTranslations,N=e.AlarmStatus},function(e){T=e},function(e){q=e,k=e.Validators,M=e.NgControl,S=e.NG_VALUE_ACCESSOR,A=e.NG_VALIDATORS,G=e.FormControl},function(e){D=e},function(e){V=e},function(e){E=e},function(e){P=e},function(e){R=e},function(e){w=e,O=e.CommonModule},function(e){H=e},function(e){U=e},function(e){K=e},function(e){B=e},function(e){j=e},function(e){z=e},function(e){_=e},function(e){Q=e,$=e.isDefinedAndNotNull,W=e.isNotEmptyStr},function(e){Y=e},function(e){J=e},function(e){Z=e.ENTER,X=e.COMMA,ee=e.SEMICOLON},function(e){te=e},function(e){oe=e},function(e){re=e},function(e){ae=e},function(e){ne=e},function(e){le=e.coerceBooleanProperty},function(e){ie=e},function(e){se=e},function(e){me=e.distinctUntilChanged,ue=e.startWith,pe=e.map,de=e.mergeMap,fe=e.share},function(e){ce=e},function(e){ge=e},function(e){xe=e.HomeComponentsModule},function(e){ye=e},function(e){be=e},function(e){he=e},function(e){Ce=e.of},function(e){Fe=e},function(e){Le=e},function(e){ve=e},function(e){Ie=e}],execute:function(){class Ne extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Ne),Ne.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ne,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ne.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ne,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ne,decorators:[{type:o,args:[{selector:"tb-node-empty-config",template:"
",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Te{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Te),Te.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,deps:[{token:H.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Te.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Te,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:H.DomSanitizer}]}});class qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[k.required,k.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[k.required,k.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",qe),qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qe,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qe,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qe,decorators:[{type:o,args:[{selector:"tb-action-node-assign-to-customer-config",templateUrl:"./assign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ke extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]],notifyDevice:[!e||e.notifyDevice,[]]})}}var Me;e("AttributesConfigComponent",ke),ke.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ke,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ke.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ke,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ke,decorators:[{type:o,args:[{selector:"tb-action-node-attributes-config",templateUrl:"./attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(Me||(Me={}));const Se=new Map([[Me.CUSTOMER,"tb.rulenode.originator-customer"],[Me.TENANT,"tb.rulenode.originator-tenant"],[Me.RELATED,"tb.rulenode.originator-related"],[Me.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);var Ae;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Ae||(Ae={}));const Ge=new Map([[Ae.CIRCLE,"tb.rulenode.perimeter-circle"],[Ae.POLYGON,"tb.rulenode.perimeter-polygon"]]);var De;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(De||(De={}));const Ve=new Map([[De.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[De.SECONDS,"tb.rulenode.time-unit-seconds"],[De.MINUTES,"tb.rulenode.time-unit-minutes"],[De.HOURS,"tb.rulenode.time-unit-hours"],[De.DAYS,"tb.rulenode.time-unit-days"]]);var Ee;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(Ee||(Ee={}));const Pe=new Map([[Ee.METER,"tb.rulenode.range-unit-meter"],[Ee.KILOMETER,"tb.rulenode.range-unit-kilometer"],[Ee.FOOT,"tb.rulenode.range-unit-foot"],[Ee.MILE,"tb.rulenode.range-unit-mile"],[Ee.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Re;!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(Re||(Re={}));const we=new Map([[Re.TITLE,"tb.rulenode.entity-details-title"],[Re.COUNTRY,"tb.rulenode.entity-details-country"],[Re.STATE,"tb.rulenode.entity-details-state"],[Re.CITY,"tb.rulenode.entity-details-city"],[Re.ZIP,"tb.rulenode.entity-details-zip"],[Re.ADDRESS,"tb.rulenode.entity-details-address"],[Re.ADDRESS2,"tb.rulenode.entity-details-address2"],[Re.PHONE,"tb.rulenode.entity-details-phone"],[Re.EMAIL,"tb.rulenode.entity-details-email"],[Re.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Oe,He,Ue;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Oe||(Oe={})),function(e){e.ASC="ASC",e.DESC="DESC"}(He||(He={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Ue||(Ue={}));const Ke=new Map([[Ue.STANDARD,"tb.rulenode.sqs-queue-standard"],[Ue.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Be=["anonymous","basic","cert.PEM"],je=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),ze=["sas","cert.PEM"],_e=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Qe;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Qe||(Qe={}));const $e=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],We=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=ze,this.azureIotHubCredentialsTypeTranslationsMap=_e}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[k.required,k.min(1),k.max(200)]],clientId:[e?e.clientId:null,[k.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[k.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),o=t.get("type").value;switch(e&&t.reset({type:o},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),o){case"sas":t.get("sasKey").setValidators([k.required]);break;case"cert.PEM":t.get("privateKey").setValidators([k.required]),t.get("privateKeyFileName").setValidators([k.required]),t.get("cert").setValidators([k.required]),t.get("certFileName").setValidators([k.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ye,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ye,selector:"tb-action-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:B.MatAccordion,selector:"mat-accordion",inputs:["multi","displayMode","togglePosition","hideToggle"],exportAs:["matAccordion"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:q.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:w.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ye,decorators:[{type:o,args:[{selector:"tb-action-node-azure-iot-hub-config",templateUrl:"./azure-iot-hub-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueId:[e?e.queueId:null,[k.required]]})}}e("CheckPointConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Je,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Je,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:_.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","required","queueType","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Je,decorators:[{type:o,args:[{selector:"tb-action-node-check-point-config",templateUrl:"./check-point-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ze extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[k.required]],alarmType:[e?e.alarmType:null,[k.required]]})}testScript(){const e=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/clear_alarm_node_script_fn").subscribe((e=>{e&&this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ze,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ze,decorators:[{type:o,args:[{selector:"tb-action-node-clear-alarm-config",templateUrl:"./clear-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Xe extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r,this.alarmSeverities=Object.keys(d),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[k.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData"]}updateValidators(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([k.required]),this.createAlarmConfigForm.get("severity").setValidators([k.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})}testScript(){const e=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(e,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/create_alarm_node_script_fn").subscribe((e=>{e&&this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(e)}))}removeKey(e,t){const o=this.createAlarmConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.createAlarmConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;e&&!t||this.jsFuncComponent.validateOnSubmit()}}e("CreateAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xe,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Xe,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xe,decorators:[{type:o,args:[{selector:"tb-action-node-create-alarm-config",templateUrl:"./create-alarm-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[k.required]],entityType:[e?e.entityType:null,[k.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[k.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[k.required,k.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([k.required,k.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([k.required,k.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:et,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:et,decorators:[{type:o,args:[{selector:"tb-action-node-create-relation-config",templateUrl:"./create-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[k.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[k.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[k.required,k.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,o=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([k.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&o?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([k.required,k.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:tt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:tt,decorators:[{type:o,args:[{selector:"tb-action-node-delete-relation-config",templateUrl:"./delete-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,k.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,k.required]})}}e("DeviceProfileConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ot,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ot,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ot,decorators:[{type:o,args:[{selector:"tb-device-profile-config",templateUrl:"./device-profile-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class rt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[k.required,k.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[k.required,k.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[k.required]]})}prepareInputConfig(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,"rulenode/generator_node_script_fn").subscribe((e=>{e&&this.generatorConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:rt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n \n \n \n
\n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:ne.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:rt,decorators:[{type:o,args:[{selector:"tb-action-node-generator-config",templateUrl:"./generator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class at extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ae,this.perimeterTypes=Object.keys(Ae),this.perimeterTypeTranslationMap=Ge,this.rangeUnits=Object.keys(Ee),this.rangeUnitTranslationMap=Pe,this.timeUnits=Object.keys(De),this.timeUnitsTranslationMap=Ve}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[k.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[k.required]],perimeterType:[e?e.perimeterType:null,[k.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[k.required,k.min(1),k.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[k.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[k.required,k.min(1),k.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[k.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([k.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ae.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([k.required,k.min(-90),k.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([k.required,k.min(-180),k.max(180)]),this.geoActionConfigForm.get("range").setValidators([k.required,k.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([k.required])),t||o!==Ae.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([k.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",at),at.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:at,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),at.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:at,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:at,decorators:[{type:o,args:[{selector:"tb-action-node-gps-geofencing-config",templateUrl:"./gps-geo-action-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class nt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.injector=o,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.ngControl=this.injector.get(M),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const o of Object.keys(e))Object.prototype.hasOwnProperty.call(e,o)&&t.push(this.fb.group({key:[o,[k.required]],value:[e[o],[k.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[k.required]],value:["",[k.required]]}))}validate(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:nt,deps:[{token:T.Store},{token:P.TranslateService},{token:t.Injector},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:nt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:S,useExisting:n((()=>nt)),multi:!0},{provide:A,useExisting:n((()=>nt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0;align-self:baseline}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:re.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{type:q.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{type:D.MatLabel,selector:"mat-label"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:se.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:nt,decorators:[{type:o,args:[{selector:"tb-kv-map-config",templateUrl:"./kv-map-config.component.html",styleUrls:["./kv-map-config.component.scss"],providers:[{provide:S,useExisting:n((()=>nt)),multi:!0},{provide:A,useExisting:n((()=>nt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:t.Injector},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],required:[{type:l}]}});class lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=$e,this.ToByteStandartCharsetTypeTranslationMap=We}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],bootstrapServers:[e?e.bootstrapServers:null,[k.required]],retries:[e?e.retries:null,[k.min(0)]],batchSize:[e?e.batchSize:null,[k.min(0)]],linger:[e?e.linger:null,[k.min(0)]],bufferMemory:[e?e.bufferMemory:null,[k.min(0)]],acks:[e?e.acks:null,[k.required]],keySerializer:[e?e.keySerializer:null,[k.required]],valueSerializer:[e?e.valueSerializer:null,[k.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([k.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",lt),lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:lt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:lt,selector:"tb-action-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:lt,decorators:[{type:o,args:[{selector:"tb-action-node-kafka-config",templateUrl:"./kafka-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class it extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/log_node_script_fn").subscribe((e=>{e&&this.logConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",it),it.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:it,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),it.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:it,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:it,decorators:[{type:o,args:[{selector:"tb-action-node-log-config",templateUrl:"./log-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class st extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Be,this.credentialsTypeTranslationsMap=je,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[k.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(me()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const o=e[t];if(!o.firstChange&&o.currentValue!==o.previousValue&&o.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){$(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([k.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[k.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(k.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return o=>{t||(t=[Object.keys(o.controls)]);return(null==o?void 0:o.controls)&&t.some((t=>t.every((t=>!e(o.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",st),st.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:st,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),st.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:st,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:S,useExisting:n((()=>st)),multi:!0},{provide:A,useExisting:n((()=>st)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',components:[{type:B.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{type:B.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:B.MatExpansionPanelTitle,selector:"mat-panel-title"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:B.MatExpansionPanelDescription,selector:"mat-panel-description"},{type:B.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{type:D.MatLabel,selector:"mat-label"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:w.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{type:w.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:st,decorators:[{type:o,args:[{selector:"tb-credentials-config",templateUrl:"./credentials-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>st)),multi:!0},{provide:A,useExisting:n((()=>st)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{required:[{type:l}],disableCertPemCredentials:[{type:l}],passwordFieldRquired:[{type:l}]}});class mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[k.required]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[k.required,k.min(1),k.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&W(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{W(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",mt),mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:mt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:mt,selector:"tb-action-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n \n
tb.rulenode.client-id-hint
\n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}:host .tb-hint.client-id{margin-top:-1.25em;max-width:-moz-fit-content;max-width:fit-content}:host mat-checkbox{padding-bottom:16px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:st,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:mt,decorators:[{type:o,args:[{selector:"tb-action-node-mqtt-config",templateUrl:"./mqtt-config.component.html",styleUrls:["./mqtt-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[k.required,k.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[k.required]]})}}e("MsgCountConfigComponent",ut),ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ut,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ut,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ut,decorators:[{type:o,args:[{selector:"tb-action-node-msg-count-config",templateUrl:"./msg-count-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[k.required,k.min(1),k.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([k.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([k.required,k.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",pt),pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:pt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:pt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:pt,decorators:[{type:o,args:[{selector:"tb-action-node-msg-delay-config",templateUrl:"./msg-delay-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[k.required]],topicName:[e?e.topicName:null,[k.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[k.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[k.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",dt),dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:dt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:dt,selector:"tb-action-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:z.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:dt,decorators:[{type:o,args:[{selector:"tb-action-node-pub-sub-config",templateUrl:"./pubsub-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]]})}}e("PushToCloudConfigComponent",ft),ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ft,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ft,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ft,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-cloud-config",templateUrl:"./push-to-cloud-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[k.required]]})}}e("PushToEdgeConfigComponent",ct),ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ct,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ct,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ct,decorators:[{type:o,args:[{selector:"tb-action-node-push-to-edge-config",templateUrl:"./push-to-edge-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[k.required]],port:[e?e.port:null,[k.required,k.min(1),k.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[k.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[k.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",gt),gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:gt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:gt,selector:"tb-action-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:gt,decorators:[{type:o,args:[{selector:"tb-action-node-rabbit-mq-config",templateUrl:"./rabbit-mq-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Qe)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[k.required]],requestMethod:[e?e.requestMethod:null,[k.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[k.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,o=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[k.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[k.required,k.min(1),k.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([k.min(0)])),o?this.restApiCallConfigForm.get("maxQueueSize").setValidators([k.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",xt),xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:xt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:xt,selector:"tb-action-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{type:st,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:xt,decorators:[{type:o,args:[{selector:"tb-action-node-rest-api-call-config",templateUrl:"./rest-api-call-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",yt),yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:yt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:yt,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-reply-config",templateUrl:"./rpc-reply-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[k.required,k.min(0)]]})}}e("RpcRequestConfigComponent",bt),bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:bt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:bt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:bt,decorators:[{type:o,args:[{selector:"tb-action-node-rpc-request-config",templateUrl:"./rpc-request-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[k.required,k.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[k.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",ht),ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ht,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:ht,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ht,decorators:[{type:o,args:[{selector:"tb-action-node-custom-table-config",templateUrl:"./save-to-custom-table-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ct extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,o=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([k.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([k.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([k.required,k.min(1),k.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([k.required,k.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(o?[k.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(o?[k.required,k.min(1),k.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Ct),Ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ct,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ct,selector:"tb-action-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ce.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{type:j.TogglePasswordComponent,selector:"tb-toggle-password"}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:D.MatSuffix,selector:"[matSuffix]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ct,decorators:[{type:o,args:[{selector:"tb-action-node-send-email-config",templateUrl:"./send-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ft extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[k.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[k.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([k.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Ft),Ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ft,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ft,selector:"tb-action-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:ge.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ft,decorators:[{type:o,args:[{selector:"tb-action-node-send-sms-config",templateUrl:"./send-sms-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Lt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[k.required]],accessKeyId:[e?e.accessKeyId:null,[k.required]],secretAccessKey:[e?e.secretAccessKey:null,[k.required]],region:[e?e.region:null,[k.required]]})}}e("SnsConfigComponent",Lt),Lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Lt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Lt,selector:"tb-action-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Lt,decorators:[{type:o,args:[{selector:"tb-action-node-sns-config",templateUrl:"./sns-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Ue,this.sqsQueueTypes=Object.keys(Ue),this.sqsQueueTypeTranslationsMap=Ke}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[k.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[k.required]],delaySeconds:[e?e.delaySeconds:null,[k.min(0),k.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[k.required]],secretAccessKey:[e?e.secretAccessKey:null,[k.required]],region:[e?e.region:null,[k.required]]})}}e("SqsConfigComponent",vt),vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:vt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:vt,selector:"tb-action-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:vt,decorators:[{type:o,args:[{selector:"tb-action-node-sqs-config",templateUrl:"./sqs-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class It extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[k.required,k.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",It),It.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:It,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),It.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:It,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:It,decorators:[{type:o,args:[{selector:"tb-action-node-timeseries-config",templateUrl:"./timeseries-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[k.required,k.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[k.required,k.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Nt),Nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Nt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Nt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Nt,decorators:[{type:o,args:[{selector:"tb-action-node-un-assign-to-customer-config",templateUrl:"./unassign-customer-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Tt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.entityType=x,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[k.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[k.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Tt),Tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Tt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Tt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>Tt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ye.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]},{type:be.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Tt,decorators:[{type:o,args:[{selector:"tb-device-relations-query-config",templateUrl:"./device-relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>Tt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class qt extends y{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(c),this.directionTypeTranslations=g,this.propagateChange=null}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[k.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",qt),qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:qt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:S,useExisting:n((()=>qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:he.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:qt,decorators:[{type:o,args:[{selector:"tb-relations-query-config",templateUrl:"./relations-query-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>qt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class kt extends y{constructor(e,t,o,r){super(e),this.store=e,this.translate=t,this.truncate=o,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[Z,X,ee],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(b))this.messageTypesList.push({name:h.get(b[e]),value:e})}get required(){return this.requiredValue}set required(e){this.requiredValue=le(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchMessageTypes(e))),fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ce(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const o=e.trim(),r=this.messageTypesList.find((e=>e.name===o));t=r?{name:r.name,value:r.value}:{name:o,value:o},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",kt),kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:kt,deps:[{token:T.Store},{token:P.TranslateService},{token:C.TruncatePipe},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:kt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:S,useExisting:n((()=>kt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:kt,decorators:[{type:o,args:[{selector:"tb-message-types-config",templateUrl:"./message-types-config.component.html",styleUrls:[],providers:[{provide:S,useExisting:n((()=>kt)),multi:!0}]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:C.TruncatePipe},{type:q.FormBuilder}]},propDecorators:{required:[{type:l}],label:[{type:l}],placeholder:[{type:l}],disabled:[{type:l}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class Mt{}e("RulenodeCoreConfigCommonModule",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Mt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,declarations:[nt,Tt,qt,kt,st,Te],imports:[O,F,xe],exports:[nt,Tt,qt,kt,st,Te]}),Mt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,imports:[[O,F,xe]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Mt,decorators:[{type:i,args:[{declarations:[nt,Tt,qt,kt,st,Te],imports:[O,F,xe],exports:[nt,Tt,qt,kt,st,Te]}]}]});class St{}e("RuleNodeCoreConfigActionModule",St),St.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,deps:[],target:t.ɵɵFactoryTarget.NgModule}),St.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,declarations:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft],imports:[O,F,xe,Mt],exports:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft]}),St.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,imports:[[O,F,xe,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:St,decorators:[{type:i,args:[{declarations:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft],imports:[O,F,xe,Mt],exports:[ke,It,bt,it,qe,Ze,Xe,et,pt,tt,rt,at,ut,yt,ht,Nt,Lt,vt,dt,lt,mt,gt,xt,Ct,Je,Ye,ot,Ft,ct,ft]}]}]});class At extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[k.required]],outputValueKey:[e?e.outputValueKey:null,[k.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[k.min(0),k.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([k.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:At,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:At,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:At,decorators:[{type:o,args:[{selector:"tb-enrichment-node-calculate-delta-config",templateUrl:"./calculate-delta-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("CustomerAttributesConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Gt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Gt,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Gt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-customer-attributes-config",templateUrl:"./customer-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[k.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.deviceAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.deviceAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("DeviceAttributesConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Dt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Dt,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:Tt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Dt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-device-attributes-config",templateUrl:"./device-attributes-config.component.html",styleUrls:["./device-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Vt extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.entityDetailsTranslationsMap=we,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(Re))this.entityDetailsList.push(Re[e]);this.detailsFormControl=new G(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchEntityDetails(e))),fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[k.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})}displayDetails(e){return e?this.translate.instant(we.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(this.entityDetailsList.filter((t=>this.translate.instant(we.get(Re[t])).toUpperCase().includes(e))))}return Ce(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.entityDetailsConfigForm.get("detailsList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}}addDetailsField(e){let t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Vt,deps:[{token:T.Store},{token:P.TranslateService},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Vt,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n
\n \n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Vt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-entity-details-config",templateUrl:"./entity-details-config.component.html",styleUrls:["./entity-details-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:q.FormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=v,this.fetchMode=Oe,this.fetchModes=Object.keys(Oe),this.samplingOrders=Object.keys(He),this.timeUnits=Object.values(De),this.timeUnitsTranslationMap=Ve}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[k.required]],fetchMode:[e?e.fetchMode:null,[k.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,o=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Oe.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([k.required,k.min(2),k.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),o?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([k.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([k.required,k.min(1),k.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([k.required,k.min(1),k.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([k.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const o=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Et,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Et,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:D.MatError,selector:"mat-error",inputs:["id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Et,decorators:[{type:o,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",templateUrl:"./get-telemetry-from-database-config.component.html",styleUrls:["./get-telemetry-from-database-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const o=this.originatorAttributesConfigForm.get(t).value,r=o.indexOf(e);r>=0&&(o.splice(r,1),this.originatorAttributesConfigForm.get(t).setValue(o,{emitEvent:!0}))}addKey(e,t){const o=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}o&&(o.value="")}}e("OriginatorAttributesConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Pt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Pt,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n \n \n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Pt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-attributes-config",templateUrl:"./originator-attributes-config.component.html",styleUrls:["./originator-attributes-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[k.required]]})}}e("OriginatorFieldsConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Rt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Rt,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',components:[{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Rt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-originator-fields-config",templateUrl:"./originator-fields-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[k.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("RelatedAttributesConfigComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:wt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:wt,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:wt,decorators:[{type:o,args:[{selector:"tb-enrichment-node-related-attributes-config",templateUrl:"./related-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[k.required]]})}}e("TenantAttributesConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ot,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ot,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:nt,selector:"tb-kv-map-config",inputs:["disabled","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ot,decorators:[{type:o,args:[{selector:"tb-enrichment-node-tenant-attributes-config",templateUrl:"./tenant-attributes-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Ht{}e("RulenodeCoreConfigEnrichmentModule",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ht.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,declarations:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At],imports:[O,F,Mt],exports:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At]}),Ht.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ht,decorators:[{type:i,args:[{declarations:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At],imports:[O,F,Mt],exports:[Gt,Vt,Dt,Pt,Rt,Et,wt,Ot,At]}]}]});class Ut extends s{constructor(e,t,o){super(e),this.store=e,this.translate=t,this.fb=o,this.alarmStatusTranslationsMap=I,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(N))this.alarmStatusList.push(N[e]);this.statusFormControl=new G(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ue(""),pe((e=>e||"")),de((e=>this.fetchAlarmStatus(e))),fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[k.required]]})}displayStatus(e){return e?this.translate.instant(I.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ce(t.filter((t=>this.translate.instant(I.get(N[t])).toUpperCase().includes(e))))}return Ce(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const o=t.indexOf(e);o>=0&&(t.splice(o,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ut,deps:[{token:T.Store},{token:P.TranslateService},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Ut,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:Fe.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple"],exportAs:["matAutocomplete"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ie.TbErrorComponent,selector:"tb-error",inputs:["error"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:Fe.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:Fe.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlDirective,selector:"[formControl]",inputs:["disabled","formControl","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe,async:w.AsyncPipe,highlight:Le.HighlightPipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Ut,decorators:[{type:o,args:[{selector:"tb-filter-node-check-alarm-status-config",templateUrl:"./check-alarm-status.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:P.TranslateService},{type:q.FormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[Z,X,ee]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,o=t.indexOf(e);o>=0&&(t.splice(o,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let o=e.value;if((o||"").trim()){o=o.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(o)||(e||(e=[]),e.push(o),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Kt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Kt,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{messageName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n \n \n \n \n {{metadataName}}\n close\n \n \n \n \n
tb.rulenode.separator-hint
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:te.MatChipList,selector:"mat-chip-list",inputs:["aria-orientation","multiple","compareWith","value","required","placeholder","disabled","selectable","tabIndex","errorStateMatcher"],outputs:["change","valueChange"],exportAs:["matChipList"]},{type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:te.MatChip,selector:"mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]",inputs:["color","disableRipple","tabIndex","selected","value","selectable","disabled","removable"],outputs:["selectionChange","destroyed","removed"],exportAs:["matChip"]},{type:te.MatChipRemove,selector:"[matChipRemove]"},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:te.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputSeparatorKeyCodes","placeholder","id","matChipInputFor","matChipInputAddOnBlur","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Kt,decorators:[{type:o,args:[{selector:"tb-filter-node-check-message-config",templateUrl:"./check-message-config.component.html",styleUrls:["./check-message-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(c),this.entitySearchDirectionTranslationsMap=g}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[k.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[k.required]:[]],relationType:[e?e.relationType:null,[k.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[k.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[k.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Bt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Bt,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',components:[{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]},{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:ae.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","showLabel","required","disabled"]},{type:ve.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]},{type:ye.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:D.MatLabel,selector:"mat-label"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Bt,decorators:[{type:o,args:[{selector:"tb-filter-node-check-relation-config",templateUrl:"./check-relation-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Ae,this.perimeterTypes=Object.keys(Ae),this.perimeterTypeTranslationMap=Ge,this.rangeUnits=Object.keys(Ee),this.rangeUnitTranslationMap=Pe}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[k.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[k.required]],perimeterType:[e?e.perimeterType:null,[k.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,o=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([k.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||o!==Ae.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([k.required,k.min(-90),k.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([k.required,k.min(-180),k.max(180)]),this.geoFilterConfigForm.get("range").setValidators([k.required,k.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([k.required])),t||o!==Ae.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([k.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:jt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:jt,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:V.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex","aria-label","aria-labelledby","id","labelPosition","name","required","checked","disabled","indeterminate","aria-describedby","value"],outputs:["change","indeterminateChange"],exportAs:["matCheckbox"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:E.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{type:q.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{type:q.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{type:q.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:jt,decorators:[{type:o,args:[{selector:"tb-filter-node-gps-geofencing-config",templateUrl:"./gps-geo-filter-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[k.required]]})}}e("MessageTypeConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:zt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:zt,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',components:[{type:kt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:zt,decorators:[{type:o,args:[{selector:"tb-filter-node-message-type-config",templateUrl:"./message-type-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[k.required]]})}}e("OriginatorTypeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:_t,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:_t,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}\n"],components:[{type:Ie.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","allowedEntityTypes","ignoreAuthorityFilter"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:E.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:_t,decorators:[{type:o,args:[{selector:"tb-filter-node-originator-type-config",templateUrl:"./originator-type-config.component.html",styleUrls:["./originator-type-config.component.scss"]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Qt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/filter_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Qt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Qt,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Qt,decorators:[{type:o,args:[{selector:"tb-filter-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class $t extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/switch_node_script_fn").subscribe((e=>{e&&this.switchConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:$t,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:$t,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:$t,decorators:[{type:o,args:[{selector:"tb-filter-node-switch-config",templateUrl:"./switch-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Wt{}e("RuleNodeCoreConfigFilterModule",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,declarations:[Kt,Bt,jt,zt,_t,Qt,$t,Ut],imports:[O,F,Mt],exports:[Kt,Bt,jt,zt,_t,Qt,$t,Ut]}),Wt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Wt,decorators:[{type:i,args:[{declarations:[Kt,Bt,jt,zt,_t,Qt,$t,Ut],imports:[O,F,Mt],exports:[Kt,Bt,jt,zt,_t,Qt,$t,Ut]}]}]});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Me,this.originatorSources=Object.keys(Me),this.originatorSourceTranslationMap=Se}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[k.required]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===Me.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([k.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Yt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Yt,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n
\n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]},{type:qt,selector:"tb-relations-query-config",inputs:["disabled","required"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Yt,decorators:[{type:o,args:[{selector:"tb-transformation-node-change-originator-config",templateUrl:"./change-originator-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Jt extends s{constructor(e,t,o,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=o,this.translate=r}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[k.required]]})}testScript(){const e=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(e,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,"rulenode/transformation_node_script_fn").subscribe((e=>{e&&this.scriptConfigForm.get("jsScript").setValue(e)}))}onValidate(){this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Jt,deps:[{token:T.Store},{token:q.FormBuilder},{token:Q.NodeScriptTestService},{token:P.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Jt,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n \n
\n
\n',components:[{type:Y.JsFuncComponent,selector:"tb-js-func",inputs:["functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","noValidate","required"]},{type:J.MatButton,selector:"button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Jt,decorators:[{type:o,args:[{selector:"tb-transformation-node-script-config",templateUrl:"./script-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder},{type:Q.NodeScriptTestService},{type:P.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!0}]}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[k.required]],toTemplate:[e?e.toTemplate:null,[k.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[k.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[k.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ue([null==e?void 0:e.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(k.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Zt,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:Zt,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',components:[{type:D.MatFormField,selector:"mat-form-field",inputs:["color","floatLabel","appearance","hideRequiredMarker","hintLabel"],exportAs:["matFormField"]},{type:U.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex"],exportAs:["matSelect"]},{type:K.MatOption,selector:"mat-option",exportAs:["matOption"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:D.MatLabel,selector:"mat-label"},{type:P.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{type:R.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["id","disabled","required","type","value","readonly","placeholder","errorStateMatcher","aria-describedby"],exportAs:["matInput"]},{type:q.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]},{type:w.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{type:D.MatError,selector:"mat-error",inputs:["id"]},{type:D.MatHint,selector:"mat-hint",inputs:["align","id"]},{type:w.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}],pipes:{translate:P.TranslatePipe,safeHtml:Te}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Zt,decorators:[{type:o,args:[{selector:"tb-transformation-node-to-email-config",templateUrl:"./to-email-config.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class Xt{}e("RulenodeCoreConfigTransformModule",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,declarations:[Yt,Jt,Zt],imports:[O,F,Mt],exports:[Yt,Jt,Zt]}),Xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:Xt,decorators:[{type:i,args:[{declarations:[Yt,Jt,Zt],imports:[O,F,Mt],exports:[Yt,Jt,Zt]}]}]});class eo extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[k.required]]})}}e("RuleChainInputComponent",eo),eo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:eo,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),eo.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:eo,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',components:[{type:ve.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","required","disabled"],outputs:["entityChanged"]}],directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{type:q.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{type:q.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{type:q.FormControlName,selector:"[formControlName]",inputs:["disabled","formControlName","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:eo,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-input-config",templateUrl:"./rule-chain-input.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class to extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",to),to.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:to,deps:[{token:T.Store},{token:q.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),to.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"12.0.0",version:"12.2.15",type:to,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',directives:[{type:E.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{type:q.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{type:q.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]}],pipes:{translate:P.TranslatePipe}}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:to,decorators:[{type:o,args:[{selector:"tb-flow-node-rule-chain-output-config",templateUrl:"./rule-chain-output.component.html",styleUrls:[]}]}],ctorParameters:function(){return[{type:T.Store},{type:q.FormBuilder}]}});class oo{}e("RuleNodeCoreConfigFlowModule",oo),oo.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,deps:[],target:t.ɵɵFactoryTarget.NgModule}),oo.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,declarations:[eo,to],imports:[O,F,Mt],exports:[eo,to]}),oo.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,imports:[[O,F,Mt]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:oo,decorators:[{type:i,args:[{declarations:[eo,to],imports:[O,F,Mt],exports:[eo,to]}]}]});class ro{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","notify-device":"Notify Device","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","latest-timeseries":"Latest timeseries","timeseries-key":"Timeseries key","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file *","private-key":"Client private key file *",cert:"Client certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",ro),ro.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,deps:[{token:P.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),ro.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,declarations:[Ne],imports:[O,F],exports:[St,Wt,Ht,Xt,oo,Ne]}),ro.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,imports:[[O,F],St,Wt,Ht,Xt,oo]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"12.2.15",ngImport:t,type:ro,decorators:[{type:i,args:[{declarations:[Ne],imports:[O,F],exports:[St,Wt,Ht,Xt,oo,Ne]}]}],ctorParameters:function(){return[{type:P.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From 321730ed0220d595354464ac7f486f7406319fb1 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 11 May 2022 23:02:03 +0200 Subject: [PATCH 29/58] added upgrade for queues --- .../main/data/upgrade/3.3.4/schema_update.sql | 30 ++++++ .../3.3.4/schema_update_device_profile.sql | 49 ++++++++++ .../install/ThingsboardInstallService.java | 1 + .../install/SqlDatabaseUpgradeService.java | 98 +++++++++++++++++++ .../TbRuleEngineQueueConfigService.java | 48 +++++++++ .../update/DefaultCacheCleanupService.java | 4 + .../queue/TbQueueServiceDeprecated.java | 28 ------ .../server/dao/rule/RuleChainService.java | 2 + .../DefaultTbQueueServiceDeprecated.java | 61 ------------ .../settings/TbQueueRuleEngineSettings.java | 24 +---- .../server/dao/rule/BaseRuleChainService.java | 8 ++ .../rule/engine/flow/TbCheckpointNode.java | 7 -- .../flow/TbCheckpointNodeConfiguration.java | 6 +- 13 files changed, 244 insertions(+), 122 deletions(-) create mode 100644 application/src/main/data/upgrade/3.3.4/schema_update.sql create mode 100644 application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql create mode 100644 application/src/main/java/org/thingsboard/server/service/install/TbRuleEngineQueueConfigService.java delete mode 100644 common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java delete mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java diff --git a/application/src/main/data/upgrade/3.3.4/schema_update.sql b/application/src/main/data/upgrade/3.3.4/schema_update.sql new file mode 100644 index 0000000000..2559de38df --- /dev/null +++ b/application/src/main/data/upgrade/3.3.4/schema_update.sql @@ -0,0 +1,30 @@ +-- +-- 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. +-- + +CREATE TABLE IF NOT EXISTS queue ( + id uuid NOT NULL CONSTRAINT queue_pkey PRIMARY KEY, + created_time bigint NOT NULL, + tenant_id uuid, + name varchar(255), + topic varchar(255), + poll_interval int, + partitions int, + consumer_per_partition boolean, + pack_processing_timeout bigint, + submit_strategy varchar(255), + processing_strategy varchar(255), + additional_info varchar +); diff --git a/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql b/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql new file mode 100644 index 0000000000..5f739e3a98 --- /dev/null +++ b/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql @@ -0,0 +1,49 @@ +-- +-- 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 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; +$$; + +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 +$$; + +ALTER TABLE device_profile + DROP COLUMN IF EXISTS default_queue_name; diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 4c8e4333a6..5ed8f588e2 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -219,6 +219,7 @@ public class ThingsboardInstallService { databaseEntitiesUpgradeService.upgradeDatabase("3.3.3"); case "3.3.4": log.info("Upgrading ThingsBoard from version 3.3.4 to 3.4.0 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.3.4"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index f7b9e5cad1..473f3accda 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -15,18 +15,31 @@ */ package org.thingsboard.server.service.install; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.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.RuleNode; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.queue.QueueService; +import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.service.install.sql.SqlDbHelper; @@ -43,7 +56,9 @@ import java.sql.SQLSyntaxErrorException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO; import static org.thingsboard.server.service.install.DatabaseHelper.ASSIGNED_CUSTOMERS; @@ -101,6 +116,14 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @Autowired private ApiUsageStateService apiUsageStateService; + @Autowired + private QueueService queueService; + + @Autowired + private TbRuleEngineQueueConfigService queueConfig; + + @Autowired + private RuleChainService ruleChainService; @Override public void upgradeDatabase(String fromVersion) throws Exception { @@ -534,6 +557,81 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.3.4": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + + log.info("Loading queues..."); + try { + if (!CollectionUtils.isEmpty(queueConfig.getQueues())) { + queueConfig.getQueues().forEach(queueSettings -> { + Queue queue = new Queue(); + queue.setTenantId(TenantId.SYS_TENANT_ID); + queue.setName(queueSettings.getName()); + queue.setTopic(queueSettings.getTopic()); + queue.setPollInterval(queueSettings.getPollInterval()); + queue.setPartitions(queueSettings.getPartitions()); + queue.setPackProcessingTimeout(queueSettings.getPackProcessingTimeout()); + SubmitStrategy submitStrategy = new SubmitStrategy(); + submitStrategy.setBatchSize(queueSettings.getSubmitStrategy().getBatchSize()); + submitStrategy.setType(SubmitStrategyType.valueOf(queueSettings.getSubmitStrategy().getType())); + queue.setSubmitStrategy(submitStrategy); + ProcessingStrategy processingStrategy = new ProcessingStrategy(); + processingStrategy.setType(ProcessingStrategyType.valueOf(queueSettings.getProcessingStrategy().getType())); + processingStrategy.setRetries(queueSettings.getProcessingStrategy().getRetries()); + processingStrategy.setFailurePercentage(queueSettings.getProcessingStrategy().getFailurePercentage()); + processingStrategy.setPauseBetweenRetries(queueSettings.getProcessingStrategy().getPauseBetweenRetries()); + processingStrategy.setMaxPauseBetweenRetries(queueSettings.getProcessingStrategy().getMaxPauseBetweenRetries()); + queue.setProcessingStrategy(processingStrategy); + queue.setConsumerPerPartition(queueSettings.isConsumerPerPartition()); + queueService.saveQueue(queue); + }); + } else { + systemDataLoaderService.createQueues(); + } + } 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 checkpoint rule nodes..."); + PageLink pageLink = new PageLink(100); + PageData pageData; + do { + pageData = tenantService.findTenants(pageLink); + for (Tenant tenant : pageData.getData()) { + TenantId tenantId = tenant.getId(); + Map queues = + queueService.findQueuesByTenantId(tenantId).stream().collect(Collectors.toMap(Queue::getName, Queue::getId)); + try { + List checkpointNodes = + ruleChainService.findRuleNodesByTenantIdAndType(tenantId, "org.thingsboard.rule.engine.flow.TbCheckpointNode"); + checkpointNodes.forEach(node -> { + ObjectNode configuration = (ObjectNode) node.getConfiguration(); + JsonNode queueNameNode = configuration.remove("queueName"); + if (queueNameNode != null) { + String queueName = queueNameNode.asText(); + configuration.put("queueId", queues.get(queueName).toString()); + ruleChainService.saveRuleNode(tenantId, node); + } + }); + } catch (Exception e) { + } + } + pageLink = pageLink.nextPageLink(); + } while (pageData.hasNext()); + + log.info("Updating schema settings..."); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;"); + log.info("Schema updated."); + } catch (Exception e) { + log.error("Failed updating schema!!!", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/TbRuleEngineQueueConfigService.java b/application/src/main/java/org/thingsboard/server/service/install/TbRuleEngineQueueConfigService.java new file mode 100644 index 0000000000..1125467082 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/TbRuleEngineQueueConfigService.java @@ -0,0 +1,48 @@ +/** + * 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.install; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; + +import javax.annotation.PostConstruct; +import java.util.List; + +@Slf4j +@Data +@EnableAutoConfiguration +@Configuration +@ConfigurationProperties(prefix = "queue.rule-engine") +@Profile("install") +public class TbRuleEngineQueueConfigService { + + private String topic; + private List queues; + + @PostConstruct + public void validate() { + queues.stream().filter(queue -> queue.getName().equals("Main")).findFirst().orElseThrow(() -> { + log.error("Main queue is not configured in thingsboard.yml"); + return new RuntimeException("No \"Main\" queue configured!"); + }); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java index c41eebdbb6..d099f4fb7c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -68,6 +68,10 @@ public class DefaultCacheCleanupService implements CacheCleanupService { log.info("Clear cache to upgrade from version 3.3.3 to 3.3.4 ..."); clearAll(); break; + case "3.3.4": + log.info("Clear cache to upgrade from version 3.3.4 to 3.4.0 ..."); + clearCacheByName("deviceProfiles"); + break; default: //Do nothing, since cache cleanup is optional. } diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java deleted file mode 100644 index 2328893abe..0000000000 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueServiceDeprecated.java +++ /dev/null @@ -1,28 +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.queue; - -import org.thingsboard.server.common.msg.queue.ServiceType; - -import java.util.Set; - -public interface TbQueueServiceDeprecated { - - Set getQueuesByServiceType(ServiceType serviceType); - - String resolve(ServiceType serviceType, String queueName); - -} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index 5089a6286e..1d99534636 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -92,5 +92,7 @@ public interface RuleChainService { List findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString); + List findRuleNodesByTenantIdAndType(TenantId tenantId, String type); + RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java b/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java deleted file mode 100644 index 8f4175dad1..0000000000 --- a/common/queue/src/main/java/org/thingsboard/server/queue/DefaultTbQueueServiceDeprecated.java +++ /dev/null @@ -1,61 +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.queue; - -import lombok.RequiredArgsConstructor; -import org.springframework.util.StringUtils; -import org.thingsboard.server.common.msg.queue.ServiceQueue; -import org.thingsboard.server.common.msg.queue.ServiceType; -import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; -import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; - -import javax.annotation.PostConstruct; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.stream.Collectors; - -//@Service -@RequiredArgsConstructor -public class DefaultTbQueueServiceDeprecated implements TbQueueServiceDeprecated { - - private final TbQueueRuleEngineSettings ruleEngineSettings; - private Set ruleEngineQueues; - - @PostConstruct - public void init() { - ruleEngineQueues = ruleEngineSettings.getQueues().stream() - .map(TbRuleEngineQueueConfiguration::getName).collect(Collectors.toCollection(LinkedHashSet::new)); - } - - @Override - public Set getQueuesByServiceType(ServiceType type) { - if (type == ServiceType.TB_RULE_ENGINE) { - return ruleEngineQueues; - } else { - return Collections.emptySet(); - } - } - - @Override - public String resolve(ServiceType serviceType, String queueName) { - if (StringUtils.isEmpty(queueName) || !getQueuesByServiceType(serviceType).contains(queueName)) { - return ServiceQueue.MAIN; - } else { - return queueName; - } - } -} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueRuleEngineSettings.java b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueRuleEngineSettings.java index eed0b8a910..eee70e9e22 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueRuleEngineSettings.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueRuleEngineSettings.java @@ -16,32 +16,14 @@ package org.thingsboard.server.queue.settings; import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; -import java.util.List; - -@Slf4j @Data -@EnableAutoConfiguration -@Configuration -@ConfigurationProperties(prefix = "queue.rule-engine") +@Component public class TbQueueRuleEngineSettings { + @Value("${queue.rule-engine.topic}") private String topic; - private List queues; - - @PostConstruct - public void validate() { - queues.stream().filter(queue -> queue.getName().equals("Main")).findFirst().orElseThrow(() -> { - log.error("Main queue is not configured in thingsboard.yml"); - return new RuntimeException("No \"Main\" queue configured!"); - }); - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 097779f33e..166d142baf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -668,6 +668,14 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search); } + @Override + public List findRuleNodesByTenantIdAndType(TenantId tenantId, String type) { + log.trace("Executing findRuleNodes, tenantId [{}], type {}", tenantId, type); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateString(type, "Incorrect type of the rule node"); + return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, ""); + } + @Override public RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode) { return ruleNodeDao.save(tenantId, ruleNode); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java index 9bd51dfdf4..470a774b90 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java @@ -24,7 +24,6 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; -import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.TbMsg; @Slf4j @@ -44,12 +43,6 @@ public class TbCheckpointNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class); - if (config.getQueueId() == null) { - Queue foundQueue = ctx.getQueueService().findQueueByTenantIdAndName(ctx.getTenantId(), config.getQueueName()); - if (foundQueue != null) { - config.setQueueId(foundQueue.getId()); - } - } } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java index b2da9142d7..0546732874 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java @@ -22,14 +22,10 @@ import org.thingsboard.server.common.data.id.QueueId; @Data public class TbCheckpointNodeConfiguration implements NodeConfiguration { - private String queueName; - private QueueId queueId; @Override public TbCheckpointNodeConfiguration defaultConfiguration() { - TbCheckpointNodeConfiguration configuration = new TbCheckpointNodeConfiguration(); - configuration.setQueueName("HighPriority"); - return configuration; + return new TbCheckpointNodeConfiguration(); } } From b85e33bf1045904abe45a3c1b106b68e29099a4d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 13 May 2022 17:58:08 +0300 Subject: [PATCH 30/58] refactoring: - Dashboard controller --- .../controller/DashboardController.java | 307 ++++-------------- .../entitiy/AbstractTbEntityService.java | 4 +- .../dashboard/DefaultTbDashboardService.java | 254 +++++++++++++++ .../entitiy/dashboard/TbDashboardService.java | 43 +++ 4 files changed, 363 insertions(+), 245 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 49c33045a5..98fc25cc54 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -22,6 +22,7 @@ import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.Example; import io.swagger.annotations.ExampleProperty; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -41,7 +42,6 @@ import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HomeDashboard; import org.thingsboard.server.common.data.HomeDashboardInfo; -import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; @@ -55,13 +55,12 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entitiy.dashboard.TbDashboardService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; @@ -90,9 +89,11 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI @RestController @TbCoreComponent +@RequiredArgsConstructor @RequestMapping("/api") public class DashboardController extends BaseController { + private final TbDashboardService tbDashboardService; public static final String DASHBOARD_ID = "dashboardId"; private static final String HOME_DASHBOARD_ID = "homeDashboardId"; @@ -180,28 +181,9 @@ public class DashboardController extends BaseController { public Dashboard saveDashboard( @ApiParam(value = "A JSON value representing the dashboard.") @RequestBody Dashboard dashboard) throws ThingsboardException { - try { - dashboard.setTenantId(getCurrentUser().getTenantId()); - - checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD); - - Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); - - logEntityAction(savedDashboard.getId(), savedDashboard, - null, - dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); - - if (dashboard.getId() != null) { - sendEntityNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), EdgeEventActionType.UPDATED); - } - - return savedDashboard; - } catch (Exception e) { - logEntityAction(emptyId(EntityType.DASHBOARD), dashboard, - null, dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); - - throw handleException(e); - } + dashboard.setTenantId(getCurrentUser().getTenantId()); + checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD); + return tbDashboardService.save(dashboard, getCurrentUser()); } @ApiOperation(value = "Delete the Dashboard (deleteDashboard)", @@ -251,30 +233,13 @@ public class DashboardController extends BaseController { @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { checkParameter(CUSTOMER_ID, strCustomerId); checkParameter(DASHBOARD_ID, strDashboardId); - try { - CustomerId customerId = new CustomerId(toUUID(strCustomerId)); - Customer customer = checkCustomerId(customerId, Operation.READ); - - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - - Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); - logEntityAction(dashboardId, savedDashboard, - customerId, - ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, strCustomerId, customer.getName()); + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + Customer customer = checkCustomerId(customerId, Operation.READ); - sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); - - return savedDashboard; - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.ASSIGNED_TO_CUSTOMER, e, strDashboardId, strCustomerId); - - throw handleException(e); - } + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); + return tbDashboardService.assignDashboardToCustomer(getTenantId(), dashboardId, customer, getCurrentUser()); } @ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)", @@ -331,69 +296,14 @@ public class DashboardController extends BaseController { @ApiParam(value = "JSON array with the list of customer ids, or empty to remove all customers") @RequestBody(required = false) String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); - try { - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - - Set customerIds = new HashSet<>(); - if (strCustomerIds != null) { - for (String strCustomerId : strCustomerIds) { - customerIds.add(new CustomerId(toUUID(strCustomerId))); - } - } - - Set addedCustomerIds = new HashSet<>(); - Set removedCustomerIds = new HashSet<>(); - for (CustomerId customerId : customerIds) { - if (!dashboard.isAssignedToCustomer(customerId)) { - addedCustomerIds.add(customerId); - } - } - - Set assignedCustomers = dashboard.getAssignedCustomers(); - if (assignedCustomers != null) { - for (ShortCustomerInfo customerInfo : assignedCustomers) { - if (!customerIds.contains(customerInfo.getCustomerId())) { - removedCustomerIds.add(customerInfo.getCustomerId()); - } - } - } - - if (addedCustomerIds.isEmpty() && removedCustomerIds.isEmpty()) { - return dashboard; - } else { - Dashboard savedDashboard = null; - for (CustomerId customerId : addedCustomerIds) { - savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); - ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); - logEntityAction(dashboardId, savedDashboard, - customerId, - ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); - sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); - } - for (CustomerId customerId : removedCustomerIds) { - ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); - savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); - logEntityAction(dashboardId, dashboard, - customerId, - ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); - sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); - } - return savedDashboard; - } - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.ASSIGNED_TO_CUSTOMER, e, strDashboardId); - - throw handleException(e); - } + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); + return tbDashboardService.updateDashboardCustomers(getTenantId(), dashboard, strCustomerIds, getCurrentUser()); } @ApiOperation(value = "Adds the Dashboard Customers (addDashboardCustomers)", notes = "Adds the list of Customers to the existing list of assignments for the Dashboard. Keeps previous assignments to customers that are not in the provided list. " + - "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, + "Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -405,42 +315,9 @@ public class DashboardController extends BaseController { @ApiParam(value = "JSON array with the list of customer ids") @RequestBody String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); - try { - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - - Set customerIds = new HashSet<>(); - if (strCustomerIds != null) { - for (String strCustomerId : strCustomerIds) { - CustomerId customerId = new CustomerId(toUUID(strCustomerId)); - if (!dashboard.isAssignedToCustomer(customerId)) { - customerIds.add(customerId); - } - } - } - - if (customerIds.isEmpty()) { - return dashboard; - } else { - Dashboard savedDashboard = null; - for (CustomerId customerId : customerIds) { - savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); - ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); - logEntityAction(dashboardId, savedDashboard, - customerId, - ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); - sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); - } - return savedDashboard; - } - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.ASSIGNED_TO_CUSTOMER, e, strDashboardId); - - throw handleException(e); - } + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); + return tbDashboardService.addDashboardCustomers(getTenantId(), dashboard, strCustomerIds, getCurrentUser()); } @ApiOperation(value = "Remove the Dashboard Customers (removeDashboardCustomers)", @@ -457,42 +334,10 @@ public class DashboardController extends BaseController { @ApiParam(value = "JSON array with the list of customer ids") @RequestBody String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); - try { - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); + return tbDashboardService.removeDashboardCustomers(getTenantId(), dashboard, strCustomerIds, getCurrentUser()); - Set customerIds = new HashSet<>(); - if (strCustomerIds != null) { - for (String strCustomerId : strCustomerIds) { - CustomerId customerId = new CustomerId(toUUID(strCustomerId)); - if (dashboard.isAssignedToCustomer(customerId)) { - customerIds.add(customerId); - } - } - } - - if (customerIds.isEmpty()) { - return dashboard; - } else { - Dashboard savedDashboard = null; - for (CustomerId customerId : customerIds) { - ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); - savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); - logEntityAction(dashboardId, dashboard, - customerId, - ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); - sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); - } - return savedDashboard; - } - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.UNASSIGNED_FROM_CUSTOMER, e, strDashboardId); - - throw handleException(e); - } } @ApiOperation(value = "Assign the Dashboard to Public Customer (assignDashboardToPublicCustomer)", @@ -510,26 +355,10 @@ public class DashboardController extends BaseController { @ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); - try { - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId()); - Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, publicCustomer.getId())); - - logEntityAction(dashboardId, savedDashboard, - publicCustomer.getId(), - ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, publicCustomer.getId().toString(), publicCustomer.getName()); - - return savedDashboard; - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.ASSIGNED_TO_CUSTOMER, e, strDashboardId); - - throw handleException(e); - } - } + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); + return tbDashboardService.assignDashboardToPublicCustomer(getTenantId(), dashboardId, getCurrentUser()); + } @ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)", notes = "Unassigns the dashboard from a special, auto-generated 'Public' Customer. Once unassigned, unauthenticated users may no longer browse the dashboard. " + @@ -775,6 +604,7 @@ public class DashboardController extends BaseController { public void setTenantHomeDashboardInfo( @ApiParam(value = "A JSON object that represents home dashboard id and other parameters", required = true) @RequestBody HomeDashboardInfo homeDashboardInfo) throws ThingsboardException { + try { if (homeDashboardInfo.getDashboardId() != null) { checkDashboardId(homeDashboardInfo.getDashboardId(), Operation.READ); @@ -847,30 +677,34 @@ public class DashboardController extends BaseController { @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { checkParameter("edgeId", strEdgeId); checkParameter(DASHBOARD_ID, strDashboardId); - try { - EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); - Edge edge = checkEdgeId(edgeId, Operation.READ); - - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - checkDashboardId(dashboardId, Operation.READ); - - Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(getCurrentUser().getTenantId(), dashboardId, edgeId)); - logEntityAction(dashboardId, savedDashboard, - null, - ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName()); - - sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDashboard.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); - - return savedDashboard; - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.ASSIGNED_TO_EDGE, e, strDashboardId, strEdgeId); - - throw handleException(e); - } + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + checkDashboardId(dashboardId, Operation.READ); + return tbDashboardService.asignDashboardToEdge(getTenantId(), dashboardId, edge, getCurrentUser()); +// try { +// +// +// +// Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(getCurrentUser().getTenantId(), dashboardId, edgeId)); +// +// logEntityAction(dashboardId, savedDashboard, +// null, +// ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName()); +// +// sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDashboard.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); +// +// return savedDashboard; +// } catch (Exception e) { +// +// logEntityAction(emptyId(EntityType.DASHBOARD), null, +// null, +// ActionType.ASSIGNED_TO_EDGE, e, strDashboardId, strEdgeId); +// +// throw handleException(e); +// } } @ApiOperation(value = "Unassign dashboard from edge (unassignDashboardFromEdge)", @@ -886,37 +720,22 @@ public class DashboardController extends BaseController { @ResponseBody public Dashboard unassignDashboardFromEdge(@PathVariable("edgeId") String strEdgeId, @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { - checkParameter("edgeId", strEdgeId); + checkParameter(EDGE_ID, strEdgeId); checkParameter(DASHBOARD_ID, strDashboardId); - try { - EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); - Edge edge = checkEdgeId(edgeId, Operation.READ); - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); - - Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromEdge(getCurrentUser().getTenantId(), dashboardId, edgeId)); - - logEntityAction(dashboardId, dashboard, - null, - ActionType.UNASSIGNED_FROM_EDGE, null, strDashboardId, strEdgeId, edge.getName()); - - sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDashboard.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE); - return savedDashboard; - } catch (Exception e) { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.UNASSIGNED_FROM_EDGE, e, strDashboardId, strEdgeId); + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); - throw handleException(e); - } + return tbDashboardService.unassignDeviceFromEdge(dashboard, edge, getCurrentUser()); } @ApiOperation(value = "Get Edge Dashboards (getEdgeDashboards)", - notes = "Returns a page of dashboard info objects assigned to the specified edge. " - + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, - produces = MediaType.APPLICATION_JSON_VALUE) + notes = "Returns a page of dashboard info objects assigned to the specified edge. " + + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java index e2ccc1f3d2..95bbe1e82f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java @@ -22,7 +22,6 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.User; @@ -43,6 +42,7 @@ import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.ClaimDevicesService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; @@ -106,6 +106,8 @@ public abstract class AbstractTbEntityService { protected RuleChainService ruleChainService; @Autowired protected EdgeNotificationService edgeNotificationService; + @Autowired + protected DashboardService dashboardService; protected ListenableFuture removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) { ListenableFuture> alarmsFuture = diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java new file mode 100644 index 0000000000..11fced7790 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -0,0 +1,254 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.entitiy.dashboard; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.ShortCustomerInfo; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entitiy.AbstractTbEntityService; +import org.thingsboard.server.service.security.model.SecurityUser; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@Service +@TbCoreComponent +@AllArgsConstructor +public class DefaultTbDashboardService extends AbstractTbEntityService implements TbDashboardService { + + @Override + public Dashboard save(Dashboard dashboard, SecurityUser user) throws ThingsboardException { + ActionType actionType = dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED; + TenantId tenantId = dashboard.getTenantId(); + try { + Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); + notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedDashboard.getId(), savedDashboard, + null, actionType, user); + return savedDashboard; + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), dashboard, null, actionType, user, e); + throw handleException(e); + } + } + + @Override + public Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; + CustomerId customerId = customer.getId(); + try { + Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId)); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard, + actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName()); + return savedDashboard; + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboardId.toString(), customerId.toString()); + throw handleException(e); + } + } + + @Override + public Dashboard assignDashboardToPublicCustomer(TenantId tenantId, DashboardId dashboardId, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; + try { + + Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); + Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, publicCustomer.getId())); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, user.getCustomerId(), savedDashboard, + actionType, null, user, false, dashboardId.toString(), + publicCustomer.getId().toString(), publicCustomer.getName()); + return savedDashboard; + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboardId.toString()); + throw handleException(e); + } + + } + + @Override + public Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; + try { + + + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + customerIds.add(new CustomerId(UUID.fromString(strCustomerId))); + } + } + + Set addedCustomerIds = new HashSet<>(); + Set removedCustomerIds = new HashSet<>(); + for (CustomerId customerId : customerIds) { + if (!dashboard.isAssignedToCustomer(customerId)) { + addedCustomerIds.add(customerId); + } + } + + Set assignedCustomers = dashboard.getAssignedCustomers(); + if (assignedCustomers != null) { + for (ShortCustomerInfo customerInfo : assignedCustomers) { + if (!customerIds.contains(customerInfo.getCustomerId())) { + removedCustomerIds.add(customerInfo.getCustomerId()); + } + } + } + + if (addedCustomerIds.isEmpty() && removedCustomerIds.isEmpty()) { + return dashboard; + } else { + Dashboard savedDashboard = null; + for (CustomerId customerId : addedCustomerIds) { + savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId)); + ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, + actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerInfo.getTitle()); + } + for (CustomerId customerId : removedCustomerIds) { + ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); + savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), customerId)); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, + ActionType.UNASSIGNED_FROM_CUSTOMER, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customerInfo.getTitle()); + } + return savedDashboard; + } + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboard.getId().toString()); + throw handleException(e); + } + } + + @Override + public Dashboard addDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; + try { + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); + if (!dashboard.isAssignedToCustomer(customerId)) { + customerIds.add(customerId); + } + } + } + + if (customerIds.isEmpty()) { + return dashboard; + } else { + Dashboard savedDashboard = null; + for (CustomerId customerId : customerIds) { + savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId)); + ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, + actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerInfo.getTitle()); + } + return savedDashboard; + } + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboard.getId().toString()); + throw handleException(e); + } + } + + @Override + public Dashboard removeDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; + try { + + + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); + if (dashboard.isAssignedToCustomer(customerId)) { + customerIds.add(customerId); + } + } + } + + if (customerIds.isEmpty()) { + return dashboard; + } else { + Dashboard savedDashboard = null; + for (CustomerId customerId : customerIds) { + ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); + savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), customerId)); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, + actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customerInfo.getTitle()); + } + return savedDashboard; + } + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboard.getId().toString()); + throw handleException(e); + } + } + + @Override + public Dashboard asignDashboardToEdge(TenantId tenantId, DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_EDGE; + EdgeId edgeId = edge.getId(); + try { + Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(tenantId, dashboardId, edgeId)); + notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, user.getCustomerId(), + edgeId, savedDashboard, actionType, EdgeEventActionType.ASSIGNED_TO_EDGE, user, dashboardId.toString(), + edgeId.toString(), edge.getName()); + return savedDashboard; + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, + actionType, user, e, dashboardId.toString(), edgeId.toString()); + throw handleException(e); + } + } + + @Override + public Dashboard unassignDeviceFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; + TenantId tenantId = dashboard.getTenantId(); + DashboardId dashboardId = dashboard.getId(); + EdgeId edgeId = edge.getId(); + try { + Dashboard savedDevice = checkNotNull(dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edgeId)); + + notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, user.getCustomerId(), + edgeId, dashboard, actionType, EdgeEventActionType.UNASSIGNED_FROM_EDGE, user, dashboardId.toString(), + edgeId.toString(), edge.getName()); + return savedDevice; + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboardId.toString(), edgeId.toString()); + throw handleException(e); + } + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java new file mode 100644 index 0000000000..0acb9a16c5 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java @@ -0,0 +1,43 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.entitiy.dashboard; + +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.service.entitiy.SimpleTbEntityService; +import org.thingsboard.server.service.security.model.SecurityUser; + +public interface TbDashboardService extends SimpleTbEntityService { + + Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException; + + Dashboard assignDashboardToPublicCustomer(TenantId tenantId, DashboardId dashboardId, SecurityUser user) throws ThingsboardException; + + Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + + Dashboard addDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + + Dashboard removeDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + + Dashboard asignDashboardToEdge(TenantId tenantId, DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException; + + Dashboard unassignDeviceFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException; + +} From 90a8b03bced6723c35f211d0a8115af482d5821d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 13 May 2022 23:04:16 +0300 Subject: [PATCH 31/58] refactoring: - add delete to SimpleTbEntityService --- .../controller/DashboardController.java | 27 ++---------- .../DefaultTbNotificationEntityService.java | 44 ++++++------------- .../entitiy/SimpleTbEntityService.java | 8 +++- .../entitiy/TbNotificationEntityService.java | 7 +-- .../entitiy/alarm/DefaultTbAlarmService.java | 21 +++++++-- .../service/entitiy/alarm/TbAlarmService.java | 6 +-- .../entitiy/asset/DefaultTbAssetService.java | 8 +++- .../service/entitiy/asset/TbAssetService.java | 2 +- .../customer/DefaultTbCustomerService.java | 14 +++--- .../entitiy/customer/TbCustomerService.java | 7 +-- .../dashboard/DefaultTbDashboardService.java | 18 ++++++++ .../entitiy/dashboard/TbDashboardService.java | 2 +- 12 files changed, 83 insertions(+), 81 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 98fc25cc54..bd5938e9e5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -195,29 +195,10 @@ public class DashboardController extends BaseController { @ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); - try { - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.DELETE); - - List relatedEdgeIds = findRelatedEdgeIds(getTenantId(), dashboardId); - - dashboardService.deleteDashboard(getCurrentUser().getTenantId(), dashboardId); - - logEntityAction(dashboardId, dashboard, - null, - ActionType.DELETED, null, strDashboardId); - - sendDeleteNotificationMsg(getTenantId(), dashboardId, relatedEdgeIds); - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), - null, - null, - ActionType.DELETED, e, strDashboardId); - - throw handleException(e); - } - } + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.DELETE); + tbDashboardService.delete(dashboard, dashboardId, getCurrentUser()); + } @ApiOperation(value = "Assign the Dashboard (assignDashboardToCustomer)", notes = "Assign the Dashboard to specified Customer or do nothing if the Dashboard is already assigned to that Customer. " + diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index c18e175fe2..a70d068d40 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -71,9 +71,13 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, List relatedEdgeIds, - SecurityUser user, Object... additionalInfo) { + SecurityUser user, + String body, Object... additionalInfo) { logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); - sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds); + sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); + if (entity instanceof Customer) { + tbClusterService.broadcastEntityStateChangeEvent(tenantId, customerId, ComponentLifecycleEvent.DELETED); + } } @Override @@ -126,7 +130,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS gatewayNotificationsService.onDeviceDeleted(device); tbClusterService.onDeviceDeleted(device, null); - notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user, false, additionalInfo); + notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user,null, additionalInfo); } @Override @@ -145,9 +149,9 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, SecurityUser user, Object... additionalInfo) { + public void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, SecurityUser user, Object... additionalInfo) { logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); - if (actionType == ActionType.UPDATED) { + if (actionType == ActionType.UPDATED) { sendEntityNotificationMsg(tenantId, entityId, EdgeEventActionType.UPDATED); } } @@ -191,20 +195,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS @Override public void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo) { logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo); - sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType (actionType)); - } - - @Override - public void notifyDeleteAlarm(Alarm alarm, SecurityUser user, List relatedEdgeIds) { - logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), ActionType.ALARM_DELETE, user, null); - sendAlarmDeleteNotificationMsg(alarm, relatedEdgeIds); - } - - @Override - public void notifyDeleteCustomer(Customer customer, SecurityUser user, List edgeIds) { - logEntityAction(customer.getTenantId(), customer.getId(), customer, customer.getId(), ActionType.DELETED, user, null); - sendDeleteNotificationMsg(customer.getTenantId(), customer.getId(), customer, edgeIds); - tbClusterService.broadcastEntityStateChangeEvent(customer.getTenantId(), customer.getId(), ComponentLifecycleEvent.DELETED); + sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType)); } private void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId, @@ -233,22 +224,15 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } } - protected void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, List edgeIds) { + protected void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, + List edgeIds, String body) { try { - sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null); + sendDeleteNotificationMsg(tenantId, entityId, edgeIds, body); } catch (Exception e) { log.warn("Failed to push delete " + entity.getClass().getName() + " msg to core: {}", entity, e); } } - protected void sendAlarmDeleteNotificationMsg(Alarm alarm, List relatedEdgeIds) { - try { - sendDeleteNotificationMsg(alarm.getTenantId(), alarm.getId(), relatedEdgeIds, json.writeValueAsString(alarm)); - } catch (Exception e) { - log.warn("Failed to push delete alarm msg to core: {}", alarm, e); - } - } - private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List edgeIds, String body) { if (edgeIds != null && !edgeIds.isEmpty()) { for (EdgeId edgeId : edgeIds) { @@ -289,7 +273,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS return null; } - private EdgeEventActionType edgeTypeByActionType (ActionType actionType) { + private EdgeEventActionType edgeTypeByActionType(ActionType actionType) { switch (actionType) { case ADDED: return EdgeEventActionType.ADDED; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java index 84f5658015..ea5bc92e3e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java @@ -15,11 +15,15 @@ */ package org.thingsboard.server.service.entitiy; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.service.security.model.SecurityUser; -public interface SimpleTbEntityService { +public interface SimpleTbEntityService { - T save(T entity, SecurityUser user) throws ThingsboardException; + E save(E entity, SecurityUser user) throws ThingsboardException; + + void delete (E entity, I entityId, SecurityUser user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 43c0cc4c91..70cac320d7 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.entitiy; -import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.Tenant; @@ -46,7 +45,7 @@ public interface TbNotificationEntityService { void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, List relatedEdgeIds, SecurityUser user, - Object... additionalInfo); + String body, Object... additionalInfo); void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, CustomerId customerId, E entity, @@ -80,8 +79,4 @@ public interface TbNotificationEntityService { void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, SecurityUser user, Object... additionalInfo); void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo); - - void notifyDeleteAlarm(Alarm alarm, SecurityUser user, List relatedEdgeIds); - - void notifyDeleteCustomer(Customer customer, SecurityUser user, List relatedEdgeIds); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 1fb19e3c41..ad066f2233 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -15,14 +15,17 @@ */ package org.thingsboard.server.service.entitiy.alarm; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -34,6 +37,7 @@ import java.util.List; @TbCoreComponent @AllArgsConstructor public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService { + private static final ObjectMapper json = new ObjectMapper(); @Override public Alarm save(Alarm alarm, SecurityUser user) throws ThingsboardException { @@ -76,9 +80,18 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { - List relatedEdgeIds = findRelatedEdgeIds(alarm.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteAlarm(alarm, user, relatedEdgeIds); - return alarmService.deleteAlarm(alarm.getTenantId(), alarm.getId()).isSuccessful(); + public Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException { + try { + TenantId tenantId = user.getTenantId(); + List relatedEdgeIds = findRelatedEdgeIds(tenantId, alarm.getOriginator()); + notificationEntityService.notifyDeleteEntity(tenantId, alarm.getOriginator(), alarm, user.getCustomerId(), + ActionType.DELETED, relatedEdgeIds, user, json.writeValueAsString(alarm)); + return alarmService.deleteAlarm(tenantId, alarm.getId()).isSuccessful(); + } catch (Exception e) { + throw handleException(e); + } } + + @Override + public void delete(E entity, I entityId, SecurityUser user) throws ThingsboardException {} } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index f73e44bc69..8a169b8f88 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -16,16 +16,16 @@ package org.thingsboard.server.service.entitiy.alarm; import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbAlarmService extends SimpleTbEntityService { +public interface TbAlarmService extends SimpleTbEntityService { void ack(Alarm alarm, SecurityUser user) throws ThingsboardException; void clear(Alarm alarm, SecurityUser user) throws ThingsboardException; - Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException; + Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index 3f4ce83318..559ac449b4 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -20,6 +20,7 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; @@ -28,6 +29,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -60,7 +62,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId); assetService.deleteAsset(tenantId, assetId); - notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, false, asset.toString()); + notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, + relatedEdgeIds, user, null, asset.toString()); return removeAlarmsByEntityId(tenantId, assetId); } catch (Exception e) { @@ -70,6 +73,9 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb } } + @Override + public void delete(E entity, I entityId, SecurityUser user) throws ThingsboardException { } + @Override public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java index 3bc6dadf3d..e753093ba2 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java @@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbAssetService extends SimpleTbEntityService { +public interface TbAssetService extends SimpleTbEntityService { ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index 452c71b51a..dec48a4fcb 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -19,9 +19,12 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -49,12 +52,13 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements } @Override - public void delete(Customer customer, SecurityUser user) throws ThingsboardException { - TenantId tenantId = customer.getTenantId(); + public void delete(E customer, I customerId, SecurityUser user) throws ThingsboardException { + TenantId tenantId = user.getTenantId(); try { - List relatedEdgeIds = findRelatedEdgeIds(tenantId, customer.getId()); - customerService.deleteCustomer(tenantId, customer.getId()); - notificationEntityService.notifyDeleteCustomer(customer, user, relatedEdgeIds); + List relatedEdgeIds = findRelatedEdgeIds(tenantId, customerId); + customerService.deleteCustomer(tenantId, (CustomerId) customerId); + notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, user.getCustomerId(), + ActionType.DELETED, relatedEdgeIds, user, null); } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null, ActionType.DELETED, user, e); throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java index f34d796db1..2e0d891046 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java @@ -16,12 +16,9 @@ package org.thingsboard.server.service.entitiy.customer; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; -import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbCustomerService extends SimpleTbEntityService { - - void delete(Customer customer, SecurityUser user) throws ThingsboardException; +public interface TbCustomerService extends SimpleTbEntityService { } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index 11fced7790..d375c1691f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -20,6 +20,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; @@ -28,12 +29,14 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -57,6 +60,21 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } } + @Override + public void delete(E dashboard, I dashboardId, SecurityUser user) throws ThingsboardException { + TenantId tenantId = user.getTenantId(); + try { + List relatedEdgeIds = findRelatedEdgeIds(tenantId, dashboardId); + dashboardService.deleteDashboard(tenantId, (DashboardId) dashboardId); + notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, user.getCustomerId(), + ActionType.DELETED, relatedEdgeIds, user, null); + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + ActionType.DELETED, user, e, dashboardId.toString()); + throw handleException(e); + } + } + @Override public Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java index 0acb9a16c5..88ebc93824 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbDashboardService extends SimpleTbEntityService { +public interface TbDashboardService extends SimpleTbEntityService { Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException; From 122e220f4dd08c573a14e7c2c4a9fbbc891650f0 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 14 May 2022 10:55:05 +0300 Subject: [PATCH 32/58] refactoring: - fix bug delete to SimpleTbEntityService --- .../server/controller/AlarmController.java | 2 +- .../server/controller/CustomerController.java | 8 +------- .../entitiy/DefaultTbNotificationEntityService.java | 3 ++- .../service/entitiy/SimpleTbEntityService.java | 6 +++--- .../entitiy/alarm/DefaultTbAlarmService.java | 13 ++++++------- .../entitiy/asset/DefaultTbAssetService.java | 5 ++--- .../entitiy/customer/DefaultTbCustomerService.java | 5 ++--- .../dashboard/DefaultTbDashboardService.java | 5 +---- 8 files changed, 18 insertions(+), 29 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index 939e9da8a0..e1db3c55e0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -147,7 +147,7 @@ public class AlarmController extends BaseController { try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); - return tbAlarmService.delete(alarm, getCurrentUser()); + return tbAlarmService.deleteAlarm(alarm, getCurrentUser()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 2fc4b7c748..8ce95eaaa5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -32,22 +32,16 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.customer.TbCustomerService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; -import java.util.List; - import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES; @@ -167,7 +161,7 @@ public class CustomerController extends BaseController { CustomerId customerId = new CustomerId(toUUID(strCustomerId)); Customer customer = checkCustomerId(customerId, Operation.DELETE); try { - tbCustomerService.delete(customer, getCurrentUser()); + tbCustomerService.delete(customer, customerId, getCurrentUser()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index a70d068d40..6ee9531c46 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -73,7 +73,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS List relatedEdgeIds, SecurityUser user, String body, Object... additionalInfo) { - logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); + EntityId entityIdForLogEntityAction = entity instanceof Alarm ? ((Alarm)entity).getOriginator() : entityId; + logEntityAction(tenantId, entityIdForLogEntityAction, entity, customerId, actionType, user, additionalInfo); sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); if (entity instanceof Customer) { tbClusterService.broadcastEntityStateChangeEvent(tenantId, customerId, ComponentLifecycleEvent.DELETED); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java index ea5bc92e3e..5d7f89f886 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java @@ -20,10 +20,10 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.service.security.model.SecurityUser; -public interface SimpleTbEntityService { +public interface SimpleTbEntityService { - E save(E entity, SecurityUser user) throws ThingsboardException; + E save(E entity, SecurityUser user) throws ThingsboardException; - void delete (E entity, I entityId, SecurityUser user) throws ThingsboardException; + void delete (E entity, I entityId, SecurityUser user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index ad066f2233..88cfb63e72 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -19,13 +19,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -82,16 +81,16 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Override public Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException { try { - TenantId tenantId = user.getTenantId(); - List relatedEdgeIds = findRelatedEdgeIds(tenantId, alarm.getOriginator()); - notificationEntityService.notifyDeleteEntity(tenantId, alarm.getOriginator(), alarm, user.getCustomerId(), + List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); + notificationEntityService.notifyDeleteEntity(user.getTenantId(), alarm.getId(), alarm, user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, json.writeValueAsString(alarm)); - return alarmService.deleteAlarm(tenantId, alarm.getId()).isSuccessful(); + return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { throw handleException(e); } } + @Override - public void delete(E entity, I entityId, SecurityUser user) throws ThingsboardException {} + public void delete(Alarm entity, AlarmId entityId, SecurityUser user) throws ThingsboardException {} } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index 559ac449b4..1d75e68616 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -20,7 +20,6 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; @@ -29,7 +28,6 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -73,8 +71,9 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb } } + @Override - public void delete(E entity, I entityId, SecurityUser user) throws ThingsboardException { } + public void delete(Asset entity, AssetId entityId, SecurityUser user) throws ThingsboardException {} @Override public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index dec48a4fcb..f5250c7ee9 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -19,12 +19,10 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -51,8 +49,9 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements } } + @Override - public void delete(E customer, I customerId, SecurityUser user) throws ThingsboardException { + public void delete(Customer customer, CustomerId customerId, SecurityUser user) throws ThingsboardException { TenantId tenantId = user.getTenantId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, customerId); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index d375c1691f..df36680f26 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -20,7 +20,6 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; @@ -29,7 +28,6 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -61,8 +59,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public void delete(E dashboard, I dashboardId, SecurityUser user) throws ThingsboardException { - TenantId tenantId = user.getTenantId(); + public void delete(Dashboard dashboard, DashboardId dashboardId, SecurityUser user) throws ThingsboardException { TenantId tenantId = user.getTenantId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, dashboardId); dashboardService.deleteDashboard(tenantId, (DashboardId) dashboardId); From 8bae18db71004bdc6263ac984b4112d0f70ece5b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 14 May 2022 13:46:23 +0300 Subject: [PATCH 33/58] refactoring: - add unassignDashboard to SimpleTbEntityService --- .../controller/DashboardController.java | 85 +++---------------- .../dashboard/DefaultTbDashboardService.java | 58 ++++++++++--- .../entitiy/dashboard/TbDashboardService.java | 10 ++- 3 files changed, 66 insertions(+), 87 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index bd5938e9e5..3f7bd618a8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -39,14 +39,11 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HomeDashboard; import org.thingsboard.server.common.data.HomeDashboardInfo; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; @@ -198,7 +195,7 @@ public class DashboardController extends BaseController { DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.DELETE); tbDashboardService.delete(dashboard, dashboardId, getCurrentUser()); - } + } @ApiOperation(value = "Assign the Dashboard (assignDashboardToCustomer)", notes = "Assign the Dashboard to specified Customer or do nothing if the Dashboard is already assigned to that Customer. " + @@ -220,7 +217,7 @@ public class DashboardController extends BaseController { DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - return tbDashboardService.assignDashboardToCustomer(getTenantId(), dashboardId, customer, getCurrentUser()); + return tbDashboardService.assignDashboardToCustomer(dashboardId, customer, getCurrentUser()); } @ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)", @@ -237,29 +234,11 @@ public class DashboardController extends BaseController { @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { checkParameter("customerId", strCustomerId); checkParameter(DASHBOARD_ID, strDashboardId); - try { - CustomerId customerId = new CustomerId(toUUID(strCustomerId)); - Customer customer = checkCustomerId(customerId, Operation.READ); - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); - - Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); - - logEntityAction(dashboardId, dashboard, - customerId, - ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customer.getId().toString(), customer.getName()); - - sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); - - return savedDashboard; - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.UNASSIGNED_FROM_CUSTOMER, e, strDashboardId); - - throw handleException(e); - } + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + Customer customer = checkCustomerId(customerId, Operation.READ); + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); + return tbDashboardService.unassignDashboardFromCustomer(dashboard, customer, getCurrentUser()); } @ApiOperation(value = "Update the Dashboard Customers (updateDashboardCustomers)", @@ -338,8 +317,8 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - return tbDashboardService.assignDashboardToPublicCustomer(getTenantId(), dashboardId, getCurrentUser()); - } + return tbDashboardService.assignDashboardToPublicCustomer(dashboardId, getCurrentUser()); + } @ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)", notes = "Unassigns the dashboard from a special, auto-generated 'Public' Customer. Once unassigned, unauthenticated users may no longer browse the dashboard. " + @@ -352,26 +331,9 @@ public class DashboardController extends BaseController { @ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); - try { - DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); - Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); - Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId()); - - Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, publicCustomer.getId())); - - logEntityAction(dashboardId, dashboard, - publicCustomer.getId(), - ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, publicCustomer.getId().toString(), publicCustomer.getName()); - - return savedDashboard; - } catch (Exception e) { - - logEntityAction(emptyId(EntityType.DASHBOARD), null, - null, - ActionType.UNASSIGNED_FROM_CUSTOMER, e, strDashboardId); - - throw handleException(e); - } + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); + return tbDashboardService.unassignDashboardFromPublicCustomer(dashboard, getCurrentUser()); } @ApiOperation(value = "Get Tenant Dashboards by System Administrator (getTenantDashboards)", @@ -665,27 +627,6 @@ public class DashboardController extends BaseController { DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); checkDashboardId(dashboardId, Operation.READ); return tbDashboardService.asignDashboardToEdge(getTenantId(), dashboardId, edge, getCurrentUser()); -// try { -// -// -// -// Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(getCurrentUser().getTenantId(), dashboardId, edgeId)); -// -// logEntityAction(dashboardId, savedDashboard, -// null, -// ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName()); -// -// sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDashboard.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); -// -// return savedDashboard; -// } catch (Exception e) { -// -// logEntityAction(emptyId(EntityType.DASHBOARD), null, -// null, -// ActionType.ASSIGNED_TO_EDGE, e, strDashboardId, strEdgeId); -// -// throw handleException(e); -// } } @ApiOperation(value = "Unassign dashboard from edge (unassignDashboardFromEdge)", @@ -710,7 +651,7 @@ public class DashboardController extends BaseController { DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); - return tbDashboardService.unassignDeviceFromEdge(dashboard, edge, getCurrentUser()); + return tbDashboardService.unassignDashboardFromEdge(dashboard, edge, getCurrentUser()); } @ApiOperation(value = "Get Edge Dashboards (getEdgeDashboards)", diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index df36680f26..523ae2f651 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -59,7 +59,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public void delete(Dashboard dashboard, DashboardId dashboardId, SecurityUser user) throws ThingsboardException { TenantId tenantId = user.getTenantId(); + public void delete(Dashboard dashboard, DashboardId dashboardId, SecurityUser user) throws ThingsboardException { + TenantId tenantId = user.getTenantId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, dashboardId); dashboardService.deleteDashboard(tenantId, (DashboardId) dashboardId); @@ -73,40 +74,56 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException { + public Dashboard assignDashboardToCustomer(DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; CustomerId customerId = customer.getId(); try { - Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard, + Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(user.getTenantId(), dashboardId, customerId)); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboardId, customerId, savedDashboard, actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName()); return savedDashboard; } catch (Exception e) { - notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null, actionType, user, e, dashboardId.toString(), customerId.toString()); throw handleException(e); } } @Override - public Dashboard assignDashboardToPublicCustomer(TenantId tenantId, DashboardId dashboardId, SecurityUser user) throws ThingsboardException { + public Dashboard assignDashboardToPublicCustomer(DashboardId dashboardId, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; try { - - Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); - Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, publicCustomer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, user.getCustomerId(), savedDashboard, + Customer publicCustomer = customerService.findOrCreatePublicCustomer(user.getTenantId()); + Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(user.getTenantId(), dashboardId, publicCustomer.getId())); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboardId, user.getCustomerId(), savedDashboard, actionType, null, user, false, dashboardId.toString(), publicCustomer.getId().toString(), publicCustomer.getName()); return savedDashboard; } catch (Exception e) { - notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null, actionType, user, e, dashboardId.toString()); throw handleException(e); } } + @Override + public Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; + try { + Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId()); + Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(user.getTenantId(), dashboard.getId(), publicCustomer.getId())); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(user.getTenantId(), dashboard.getId(), user.getCustomerId(), dashboard, + actionType, null, user, false, dashboard.getId().toString(), + publicCustomer.getId().toString(), publicCustomer.getName()); + return savedDashboard; + } catch (Exception e) { + notificationEntityService.notifyEntity(user.getTenantId(), emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboard.getId().toString()); + throw handleException(e); + } + } + @Override public Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; @@ -248,7 +265,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard unassignDeviceFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException { + public Dashboard unassignDashboardFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; TenantId tenantId = dashboard.getTenantId(); DashboardId dashboardId = dashboard.getId(); @@ -266,4 +283,21 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement throw handleException(e); } } + + @Override + public Dashboard unassignDashboardFromCustomer(Dashboard dashboard, Customer customer, SecurityUser user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; + TenantId tenantId = dashboard.getTenantId(); + try { + Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), customer.getId())); + notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboard.getId(), customer.getId(), savedDashboard, + actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, true, customer.getId().toString(), customer.getName()); + return savedDashboard; + } catch (Exception e) { + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, + actionType, user, e, dashboard.getId().toString()); + throw handleException(e); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java index 88ebc93824..36598f514e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java @@ -26,9 +26,11 @@ import org.thingsboard.server.service.security.model.SecurityUser; public interface TbDashboardService extends SimpleTbEntityService { - Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException; + Dashboard assignDashboardToCustomer(DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException; - Dashboard assignDashboardToPublicCustomer(TenantId tenantId, DashboardId dashboardId, SecurityUser user) throws ThingsboardException; + Dashboard assignDashboardToPublicCustomer(DashboardId dashboardId, SecurityUser user) throws ThingsboardException; + + Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, SecurityUser user) throws ThingsboardException; Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; @@ -38,6 +40,8 @@ public interface TbDashboardService extends SimpleTbEntityService Date: Sun, 15 May 2022 22:20:25 +0300 Subject: [PATCH 34/58] refactoring: - delete SimpleTbEntityService from Alarm --- .../entitiy/alarm/DefaultTbAlarmService.java | 15 +++++---------- .../service/entitiy/alarm/TbAlarmService.java | 6 +++--- .../customer/DefaultTbCustomerService.java | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 88cfb63e72..870388483e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -81,16 +80,12 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Override public Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException { try { - List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteEntity(user.getTenantId(), alarm.getId(), alarm, user.getCustomerId(), - ActionType.DELETED, relatedEdgeIds, user, json.writeValueAsString(alarm)); - return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); + List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); + notificationEntityService.notifyDeleteEntity(user.getTenantId(), alarm.getId(), alarm, user.getCustomerId(), + ActionType.DELETED, relatedEdgeIds, user, json.writeValueAsString(alarm)); + return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { throw handleException(e); } } - - - @Override - public void delete(Alarm entity, AlarmId entityId, SecurityUser user) throws ThingsboardException {} -} +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 8a169b8f88..85bff96d47 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -17,11 +17,11 @@ package org.thingsboard.server.service.entitiy.alarm; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.AlarmId; -import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbAlarmService extends SimpleTbEntityService { +public interface TbAlarmService { + + Alarm save(Alarm entity, SecurityUser user) throws ThingsboardException; void ack(Alarm alarm, SecurityUser user) throws ThingsboardException; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index f5250c7ee9..ba3141983d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -55,7 +55,7 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements TenantId tenantId = user.getTenantId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, customerId); - customerService.deleteCustomer(tenantId, (CustomerId) customerId); + customerService.deleteCustomer(tenantId, customerId); notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, null); } catch (Exception e) { From f32847a8692678e23ff787d5053a62d6244c853b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 16 May 2022 13:03:21 +0200 Subject: [PATCH 35/58] typo fix --- .../server/dao/service/validator/QueueValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java index 4875887b18..8257a6e659 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java @@ -57,7 +57,7 @@ public class QueueValidator extends DataValidator { if (!foundQueue.getName().equals(queue.getName())) { throw new DataValidationException("Queue name can't be changed!"); } - if (!foundQueue.getTopic().equals(queue.getTopic())) {QueueValidator + if (!foundQueue.getTopic().equals(queue.getTopic())) { throw new DataValidationException("Queue topic can't be changed!"); } return foundQueue; From 1e973825b74c1eecb38366b054aa0a1729128ca7 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 16 May 2022 17:54:48 +0300 Subject: [PATCH 36/58] refactoring: - dashboard commits --- .../server/controller/AssetController.java | 4 ++-- .../server/controller/CustomerController.java | 2 +- .../server/controller/DashboardController.java | 2 +- .../service/asset/AssetBulkImportService.java | 2 +- .../DefaultTbNotificationEntityService.java | 10 +++------- .../service/entitiy/SimpleTbEntityService.java | 8 +++----- .../entitiy/TbNotificationEntityService.java | 2 +- .../entitiy/alarm/DefaultTbAlarmService.java | 7 +++---- .../entitiy/asset/DefaultTbAssetService.java | 11 ++++------- .../service/entitiy/asset/TbAssetService.java | 7 ++++--- .../entitiy/customer/DefaultTbCustomerService.java | 12 +++++++++--- .../entitiy/customer/TbCustomerService.java | 3 +-- .../dashboard/DefaultTbDashboardService.java | 14 +++++--------- .../entitiy/dashboard/TbDashboardService.java | 2 +- 14 files changed, 39 insertions(+), 47 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 4718feb774..9edd328b68 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -149,7 +149,7 @@ public class AssetController extends BaseController { } asset.setTenantId(getCurrentUser().getTenantId()); checkEntity(asset.getId(), asset, Resource.ASSET); - return tbAssetService.save(asset, getCurrentUser()); + return tbAssetService.saveAsset(asset, getCurrentUser()); } @ApiOperation(value = "Delete asset (deleteAsset)", @@ -162,7 +162,7 @@ public class AssetController extends BaseController { try { AssetId assetId = new AssetId(toUUID(strAssetId)); Asset asset = checkAssetId(assetId, Operation.DELETE); - tbAssetService.delete(asset, getCurrentUser()).get(); + tbAssetService.deleteAsset(asset, getCurrentUser()).get(); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 8ce95eaaa5..a824690653 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -161,7 +161,7 @@ public class CustomerController extends BaseController { CustomerId customerId = new CustomerId(toUUID(strCustomerId)); Customer customer = checkCustomerId(customerId, Operation.DELETE); try { - tbCustomerService.delete(customer, customerId, getCurrentUser()); + tbCustomerService.delete(customer, getCurrentUser()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 3f7bd618a8..7ff16baae0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -194,7 +194,7 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.DELETE); - tbDashboardService.delete(dashboard, dashboardId, getCurrentUser()); + tbDashboardService.delete(dashboard, getCurrentUser()); } @ApiOperation(value = "Assign the Dashboard (assignDashboardToCustomer)", diff --git a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java index e9999d2dc1..834eeb555d 100644 --- a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java @@ -66,7 +66,7 @@ public class AssetBulkImportService extends AbstractBulkImportService { @Override @SneakyThrows protected Asset saveEntity(SecurityUser user, Asset entity, Map fields) { - return tbAssetService.save(entity, user); + return tbAssetService.saveAsset(entity, user); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 6ee9531c46..2cd1ae1acc 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -22,7 +22,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.HasName; @@ -68,17 +67,14 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, + public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, EntityId originatorId, CustomerId customerId, ActionType actionType, List relatedEdgeIds, SecurityUser user, String body, Object... additionalInfo) { - EntityId entityIdForLogEntityAction = entity instanceof Alarm ? ((Alarm)entity).getOriginator() : entityId; + EntityId entityIdForLogEntityAction = originatorId != null ? originatorId : entityId; logEntityAction(tenantId, entityIdForLogEntityAction, entity, customerId, actionType, user, additionalInfo); sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); - if (entity instanceof Customer) { - tbClusterService.broadcastEntityStateChangeEvent(tenantId, customerId, ComponentLifecycleEvent.DELETED); - } } @Override @@ -131,7 +127,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS gatewayNotificationsService.onDeviceDeleted(device); tbClusterService.onDeviceDeleted(device, null); - notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user,null, additionalInfo); + notifyDeleteEntity(tenantId, deviceId, device, customerId, null, ActionType.DELETED, relatedEdgeIds, user,null, additionalInfo); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java index 5d7f89f886..ce22e8d787 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java @@ -15,15 +15,13 @@ */ package org.thingsboard.server.service.entitiy; -import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.service.security.model.SecurityUser; -public interface SimpleTbEntityService { +public interface SimpleTbEntityService { - E save(E entity, SecurityUser user) throws ThingsboardException; + T save(T entity, SecurityUser user) throws ThingsboardException; - void delete (E entity, I entityId, SecurityUser user) throws ThingsboardException; + void delete (T entity, SecurityUser user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 70cac320d7..1e0bcf1124 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -43,7 +43,7 @@ public interface TbNotificationEntityService { CustomerId customerId, ActionType actionType, SecurityUser user, Object... additionalInfo); - void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, + void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, EntityId originatorId, CustomerId customerId, ActionType actionType, List relatedEdgeIds, SecurityUser user, String body, Object... additionalInfo); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 870388483e..809b8b4e8c 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -15,9 +15,9 @@ */ package org.thingsboard.server.service.entitiy.alarm; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; @@ -35,7 +35,6 @@ import java.util.List; @TbCoreComponent @AllArgsConstructor public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService { - private static final ObjectMapper json = new ObjectMapper(); @Override public Alarm save(Alarm alarm, SecurityUser user) throws ThingsboardException { @@ -81,8 +80,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb public Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException { try { List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteEntity(user.getTenantId(), alarm.getId(), alarm, user.getCustomerId(), - ActionType.DELETED, relatedEdgeIds, user, json.writeValueAsString(alarm)); + notificationEntityService.notifyDeleteEntity(user.getTenantId(), alarm.getId(), alarm, alarm.getOriginator(), user.getCustomerId(), + ActionType.DELETED, relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm)); return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index 1d75e68616..e44e405273 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -39,8 +39,9 @@ import java.util.List; @TbCoreComponent @AllArgsConstructor public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService { + @Override - public Asset save(Asset asset, SecurityUser user) throws ThingsboardException { + public Asset saveAsset(Asset asset, SecurityUser user) throws ThingsboardException { ActionType actionType = asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED; TenantId tenantId = asset.getTenantId(); try { @@ -54,13 +55,13 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb } @Override - public ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException { + public ListenableFuture deleteAsset(Asset asset, SecurityUser user) throws ThingsboardException { TenantId tenantId = asset.getTenantId(); AssetId assetId = asset.getId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId); assetService.deleteAsset(tenantId, assetId); - notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, + notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, null, asset.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, null, asset.toString()); return removeAlarmsByEntityId(tenantId, assetId); @@ -71,10 +72,6 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb } } - - @Override - public void delete(Asset entity, AssetId entityId, SecurityUser user) throws ThingsboardException {} - @Override public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java index e753093ba2..ccbd9e715e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java @@ -22,12 +22,13 @@ import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbAssetService extends SimpleTbEntityService { +public interface TbAssetService { - ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException; + Asset saveAsset(Asset asset, SecurityUser user) throws ThingsboardException; + + ListenableFuture deleteAsset (Asset asset, SecurityUser user) throws ThingsboardException; Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index ba3141983d..b3abdd1fc6 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.entitiy.customer; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; +import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; @@ -24,6 +25,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; @@ -35,6 +37,8 @@ import java.util.List; @AllArgsConstructor public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService { + private final TbClusterService tbClusterService; + @Override public Customer save(Customer customer, SecurityUser user) throws ThingsboardException { ActionType actionType = customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED; @@ -51,13 +55,15 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements @Override - public void delete(Customer customer, CustomerId customerId, SecurityUser user) throws ThingsboardException { - TenantId tenantId = user.getTenantId(); + public void delete(Customer customer, SecurityUser user) throws ThingsboardException { + TenantId tenantId = customer.getTenantId(); + CustomerId customerId = customer.getId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, customerId); customerService.deleteCustomer(tenantId, customerId); - notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, user.getCustomerId(), + notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, null, customerId, ActionType.DELETED, relatedEdgeIds, user, null); + tbClusterService.broadcastEntityStateChangeEvent(tenantId, customerId, ComponentLifecycleEvent.DELETED); } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null, ActionType.DELETED, user, e); throw handleException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java index 2e0d891046..870de10efc 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/TbCustomerService.java @@ -16,9 +16,8 @@ package org.thingsboard.server.service.entitiy.customer; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; -public interface TbCustomerService extends SimpleTbEntityService { +public interface TbCustomerService extends SimpleTbEntityService { } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index 523ae2f651..cf7a4d9413 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -59,12 +59,13 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public void delete(Dashboard dashboard, DashboardId dashboardId, SecurityUser user) throws ThingsboardException { - TenantId tenantId = user.getTenantId(); + public void delete(Dashboard dashboard, SecurityUser user) throws ThingsboardException { + TenantId tenantId = dashboard.getTenantId(); + DashboardId dashboardId = dashboard.getId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, dashboardId); - dashboardService.deleteDashboard(tenantId, (DashboardId) dashboardId); - notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, user.getCustomerId(), + dashboardService.deleteDashboard(tenantId, dashboardId); + notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null, user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, null); } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, @@ -104,7 +105,6 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement actionType, user, e, dashboardId.toString()); throw handleException(e); } - } @Override @@ -128,8 +128,6 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement public Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; try { - - Set customerIds = new HashSet<>(); if (strCustomerIds != null) { for (String strCustomerId : strCustomerIds) { @@ -216,8 +214,6 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement public Dashboard removeDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; try { - - Set customerIds = new HashSet<>(); if (strCustomerIds != null) { for (String strCustomerId : strCustomerIds) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java index 36598f514e..5daceb5510 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; -public interface TbDashboardService extends SimpleTbEntityService { +public interface TbDashboardService extends SimpleTbEntityService { Dashboard assignDashboardToCustomer(DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException; From 8852fc8f8e2524ade77fc99cbd21b0489309dd96 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 17 May 2022 08:11:19 +0200 Subject: [PATCH 37/58] enabled autoconfiguration for MeterRegistry --- .../server/coap/ThingsboardCoapTransportApplication.java | 2 ++ .../server/http/ThingsboardHttpTransportApplication.java | 2 ++ .../server/lwm2m/ThingsboardLwm2mTransportApplication.java | 2 ++ .../server/mqtt/ThingsboardMqttTransportApplication.java | 6 +++++- .../server/snmp/ThingsboardSnmpTransportApplication.java | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/transport/coap/src/main/java/org/thingsboard/server/coap/ThingsboardCoapTransportApplication.java b/transport/coap/src/main/java/org/thingsboard/server/coap/ThingsboardCoapTransportApplication.java index 49e0ef1553..2478502bcc 100644 --- a/transport/coap/src/main/java/org/thingsboard/server/coap/ThingsboardCoapTransportApplication.java +++ b/transport/coap/src/main/java/org/thingsboard/server/coap/ThingsboardCoapTransportApplication.java @@ -17,6 +17,7 @@ package org.thingsboard.server.coap; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @@ -26,6 +27,7 @@ import java.util.Arrays; @SpringBootConfiguration @EnableAsync @EnableScheduling +@EnableAutoConfiguration @ComponentScan({"org.thingsboard.server.coap", "org.thingsboard.server.common", "org.thingsboard.server.coapserver", "org.thingsboard.server.transport.coap", "org.thingsboard.server.queue", "org.thingsboard.server.cache"}) public class ThingsboardCoapTransportApplication { diff --git a/transport/http/src/main/java/org/thingsboard/server/http/ThingsboardHttpTransportApplication.java b/transport/http/src/main/java/org/thingsboard/server/http/ThingsboardHttpTransportApplication.java index 1ef3acd298..4d51a5a65a 100644 --- a/transport/http/src/main/java/org/thingsboard/server/http/ThingsboardHttpTransportApplication.java +++ b/transport/http/src/main/java/org/thingsboard/server/http/ThingsboardHttpTransportApplication.java @@ -16,6 +16,7 @@ package org.thingsboard.server.http; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; @@ -24,6 +25,7 @@ import java.util.Arrays; @SpringBootApplication @EnableAsync +@EnableAutoConfiguration @ComponentScan({"org.thingsboard.server.http", "org.thingsboard.server.common", "org.thingsboard.server.transport.http", "org.thingsboard.server.queue", "org.thingsboard.server.cache"}) public class ThingsboardHttpTransportApplication { diff --git a/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java b/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java index 6889d7c593..62406bb8b0 100644 --- a/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java +++ b/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java @@ -17,6 +17,7 @@ package org.thingsboard.server.lwm2m; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @@ -26,6 +27,7 @@ import java.util.Arrays; @SpringBootConfiguration @EnableAsync @EnableScheduling +@EnableAutoConfiguration @ComponentScan({"org.thingsboard.server.lwm2m", "org.thingsboard.server.common", "org.thingsboard.server.transport.lwm2m", "org.thingsboard.server.queue", "org.thingsboard.server.cache"}) public class ThingsboardLwm2mTransportApplication { diff --git a/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java b/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java index 08d3c2b1f9..1f64be1efe 100644 --- a/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java +++ b/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java @@ -17,6 +17,10 @@ package org.thingsboard.server.mqtt; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @@ -25,7 +29,7 @@ import java.util.Arrays; @SpringBootConfiguration @EnableAsync -@EnableScheduling +@EnableAutoConfiguration @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 { diff --git a/transport/snmp/src/main/java/org/thingsboard/server/snmp/ThingsboardSnmpTransportApplication.java b/transport/snmp/src/main/java/org/thingsboard/server/snmp/ThingsboardSnmpTransportApplication.java index 4cfa81770c..10f8341bfc 100644 --- a/transport/snmp/src/main/java/org/thingsboard/server/snmp/ThingsboardSnmpTransportApplication.java +++ b/transport/snmp/src/main/java/org/thingsboard/server/snmp/ThingsboardSnmpTransportApplication.java @@ -17,6 +17,7 @@ package org.thingsboard.server.snmp; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @@ -26,6 +27,7 @@ import java.util.Arrays; @SpringBootConfiguration @EnableAsync @EnableScheduling +@EnableAutoConfiguration @ComponentScan({"org.thingsboard.server.snmp", "org.thingsboard.server.common", "org.thingsboard.server.transport.snmp", "org.thingsboard.server.queue", "org.thingsboard.server.cache"}) public class ThingsboardSnmpTransportApplication { From 2831c58aed05606685ead912c85aa1691b4d19e8 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 17 May 2022 08:17:18 +0200 Subject: [PATCH 38/58] removed queues config from yml --- .../src/main/resources/tb-coap-transport.yml | 46 ------------------- .../src/main/resources/tb-http-transport.yml | 46 ------------------- .../src/main/resources/tb-lwm2m-transport.yml | 46 ------------------- .../src/main/resources/tb-mqtt-transport.yml | 46 ------------------- .../src/main/resources/tb-snmp-transport.yml | 46 ------------------- 5 files changed, 230 deletions(-) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index f4717c418d..39cb9b35d0 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -260,52 +260,6 @@ queue: stats: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" - queues: - - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" - topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" - poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" - topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" - poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" - topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" - poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 76e78118af..29d8a1d381 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -248,52 +248,6 @@ queue: stats: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" - queues: - - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" - topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" - poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" - topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" - poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" - topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" - poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index c9ab9c5542..361ac7c651 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -327,52 +327,6 @@ queue: stats: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" - queues: - - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" - topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" - poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" - topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" - poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" - topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" - poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 17858eeb1a..1b84701ccf 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -278,52 +278,6 @@ queue: stats: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" - queues: - - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" - topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" - poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" - topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" - poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" - topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" - poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 34dfbddcdc..7562af359b 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -228,52 +228,6 @@ queue: stats: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" - queues: - - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" - topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" - poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" - topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" - poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; - - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" - topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" - poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" - submit-strategy: - type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL - # For BATCH only - batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch - processing-strategy: - type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT - retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited - failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages; - pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries; transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" From a0a0d5dcf9863c001507c4df13bc6c96d0a08bfe Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 17 May 2022 08:19:22 +0200 Subject: [PATCH 39/58] changed log level for transports --- transport/coap/src/main/resources/logback.xml | 2 +- transport/http/src/main/resources/logback.xml | 2 +- transport/lwm2m/src/main/resources/logback.xml | 2 +- transport/mqtt/src/main/resources/logback.xml | 2 +- transport/snmp/src/main/resources/logback.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/transport/coap/src/main/resources/logback.xml b/transport/coap/src/main/resources/logback.xml index 6149e004d9..240eccaa64 100644 --- a/transport/coap/src/main/resources/logback.xml +++ b/transport/coap/src/main/resources/logback.xml @@ -25,7 +25,7 @@ - + diff --git a/transport/http/src/main/resources/logback.xml b/transport/http/src/main/resources/logback.xml index 6149e004d9..240eccaa64 100644 --- a/transport/http/src/main/resources/logback.xml +++ b/transport/http/src/main/resources/logback.xml @@ -25,7 +25,7 @@ - + diff --git a/transport/lwm2m/src/main/resources/logback.xml b/transport/lwm2m/src/main/resources/logback.xml index 6149e004d9..240eccaa64 100644 --- a/transport/lwm2m/src/main/resources/logback.xml +++ b/transport/lwm2m/src/main/resources/logback.xml @@ -25,7 +25,7 @@ - + diff --git a/transport/mqtt/src/main/resources/logback.xml b/transport/mqtt/src/main/resources/logback.xml index 6149e004d9..240eccaa64 100644 --- a/transport/mqtt/src/main/resources/logback.xml +++ b/transport/mqtt/src/main/resources/logback.xml @@ -25,7 +25,7 @@ - + diff --git a/transport/snmp/src/main/resources/logback.xml b/transport/snmp/src/main/resources/logback.xml index 6149e004d9..240eccaa64 100644 --- a/transport/snmp/src/main/resources/logback.xml +++ b/transport/snmp/src/main/resources/logback.xml @@ -25,7 +25,7 @@ - + From e59ffcdba6a4eed9c3760d6cb1146b5d6fa6f7b5 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 17 May 2022 12:07:11 +0300 Subject: [PATCH 40/58] refactoring: - dashboard delete tenantId from interface --- .../server/controller/DashboardController.java | 8 ++++---- .../entitiy/dashboard/DefaultTbDashboardService.java | 12 ++++++++---- .../entitiy/dashboard/TbDashboardService.java | 8 ++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 7ff16baae0..7a101f3571 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -258,7 +258,7 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - return tbDashboardService.updateDashboardCustomers(getTenantId(), dashboard, strCustomerIds, getCurrentUser()); + return tbDashboardService.updateDashboardCustomers(dashboard, strCustomerIds, getCurrentUser()); } @ApiOperation(value = "Adds the Dashboard Customers (addDashboardCustomers)", @@ -277,7 +277,7 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - return tbDashboardService.addDashboardCustomers(getTenantId(), dashboard, strCustomerIds, getCurrentUser()); + return tbDashboardService.addDashboardCustomers(dashboard, strCustomerIds, getCurrentUser()); } @ApiOperation(value = "Remove the Dashboard Customers (removeDashboardCustomers)", @@ -296,7 +296,7 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); - return tbDashboardService.removeDashboardCustomers(getTenantId(), dashboard, strCustomerIds, getCurrentUser()); + return tbDashboardService.removeDashboardCustomers(dashboard, strCustomerIds, getCurrentUser()); } @@ -626,7 +626,7 @@ public class DashboardController extends BaseController { DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); checkDashboardId(dashboardId, Operation.READ); - return tbDashboardService.asignDashboardToEdge(getTenantId(), dashboardId, edge, getCurrentUser()); + return tbDashboardService.asignDashboardToEdge(dashboardId, edge, getCurrentUser()); } @ApiOperation(value = "Unassign dashboard from edge (unassignDashboardFromEdge)", diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index cf7a4d9413..a9c6e7dde5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -125,8 +125,9 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + public Dashboard updateDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; + TenantId tenantId = user.getTenantId(); try { Set customerIds = new HashSet<>(); if (strCustomerIds != null) { @@ -178,8 +179,9 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard addDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + public Dashboard addDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; + TenantId tenantId = user.getTenantId(); try { Set customerIds = new HashSet<>(); if (strCustomerIds != null) { @@ -211,8 +213,9 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard removeDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + public Dashboard removeDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; + TenantId tenantId = user.getTenantId(); try { Set customerIds = new HashSet<>(); if (strCustomerIds != null) { @@ -244,8 +247,9 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard asignDashboardToEdge(TenantId tenantId, DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException { + public Dashboard asignDashboardToEdge(DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_EDGE; + TenantId tenantId = user.getTenantId(); EdgeId edgeId = edge.getId(); try { Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(tenantId, dashboardId, edgeId)); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java index 5daceb5510..2930b1c10d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java @@ -32,13 +32,13 @@ public interface TbDashboardService extends SimpleTbEntityService { Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, SecurityUser user) throws ThingsboardException; - Dashboard updateDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + Dashboard updateDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; - Dashboard addDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + Dashboard addDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; - Dashboard removeDashboardCustomers(TenantId tenantId, Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + Dashboard removeDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; - Dashboard asignDashboardToEdge(TenantId tenantId, DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException; + Dashboard asignDashboardToEdge(DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException; Dashboard unassignDashboardFromEdge(Dashboard dashboard, Edge edge, SecurityUser user) throws ThingsboardException; From 8232fc4b7018654fd0ccc723f7cd9b5f9421392b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 17 May 2022 13:58:18 +0300 Subject: [PATCH 41/58] refactoring: - dashboard comments2 --- .../server/controller/AlarmController.java | 2 +- .../server/controller/AssetController.java | 4 +- .../controller/DashboardController.java | 27 +++++++++++-- .../server/controller/DeviceController.java | 2 +- .../server/controller/EdgeController.java | 4 +- .../service/asset/AssetBulkImportService.java | 2 +- .../service/edge/EdgeBulkImportService.java | 2 +- .../DefaultTbNotificationEntityService.java | 34 ++++++++++++----- .../entitiy/TbNotificationEntityService.java | 12 ++++-- .../entitiy/alarm/DefaultTbAlarmService.java | 4 +- .../service/entitiy/alarm/TbAlarmService.java | 2 +- .../entitiy/asset/DefaultTbAssetService.java | 6 +-- .../service/entitiy/asset/TbAssetService.java | 4 +- .../customer/DefaultTbCustomerService.java | 2 +- .../dashboard/DefaultTbDashboardService.java | 38 +++---------------- .../entitiy/dashboard/TbDashboardService.java | 10 +++-- .../device/DefaultTbDeviceService.java | 2 +- .../entitiy/device/TbDeviceService.java | 2 +- .../entitiy/edge/DefaultTbEdgeService.java | 4 +- .../service/entitiy/edge/TbEdgeService.java | 4 +- 20 files changed, 91 insertions(+), 76 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index e1db3c55e0..939e9da8a0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -147,7 +147,7 @@ public class AlarmController extends BaseController { try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); - return tbAlarmService.deleteAlarm(alarm, getCurrentUser()); + return tbAlarmService.delete(alarm, getCurrentUser()); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 9edd328b68..4718feb774 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -149,7 +149,7 @@ public class AssetController extends BaseController { } asset.setTenantId(getCurrentUser().getTenantId()); checkEntity(asset.getId(), asset, Resource.ASSET); - return tbAssetService.saveAsset(asset, getCurrentUser()); + return tbAssetService.save(asset, getCurrentUser()); } @ApiOperation(value = "Delete asset (deleteAsset)", @@ -162,7 +162,7 @@ public class AssetController extends BaseController { try { AssetId assetId = new AssetId(toUUID(strAssetId)); Asset asset = checkAssetId(assetId, Operation.DELETE); - tbAssetService.deleteAsset(asset, getCurrentUser()).get(); + tbAssetService.delete(asset, getCurrentUser()).get(); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 7a101f3571..044c61001d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -39,6 +39,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HomeDashboard; import org.thingsboard.server.common.data.HomeDashboardInfo; import org.thingsboard.server.common.data.Tenant; @@ -57,7 +58,10 @@ import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID; @@ -258,7 +262,8 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - return tbDashboardService.updateDashboardCustomers(dashboard, strCustomerIds, getCurrentUser()); + Set customerIds = customerIdFromStr(strCustomerIds, dashboard); + return tbDashboardService.updateDashboardCustomers(dashboard, customerIds, getCurrentUser()); } @ApiOperation(value = "Adds the Dashboard Customers (addDashboardCustomers)", @@ -277,7 +282,8 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); - return tbDashboardService.addDashboardCustomers(dashboard, strCustomerIds, getCurrentUser()); + Set customerIds = customerIdFromStr(strCustomerIds, dashboard); + return tbDashboardService.addDashboardCustomers(dashboard, customerIds, getCurrentUser()); } @ApiOperation(value = "Remove the Dashboard Customers (removeDashboardCustomers)", @@ -296,8 +302,8 @@ public class DashboardController extends BaseController { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER); - return tbDashboardService.removeDashboardCustomers(dashboard, strCustomerIds, getCurrentUser()); - + Set customerIds = customerIdFromStr(strCustomerIds, dashboard); + return tbDashboardService.removeDashboardCustomers(dashboard, customerIds, getCurrentUser()); } @ApiOperation(value = "Assign the Dashboard to Public Customer (assignDashboardToPublicCustomer)", @@ -698,4 +704,17 @@ public class DashboardController extends BaseController { throw handleException(e); } } + + private Set customerIdFromStr(String [] strCustomerIds, Dashboard dashboard) { + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); + if (dashboard.isAssignedToCustomer(customerId)) { + customerIds.add(customerId); + } + } + } + return customerIds; + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index f7b3908010..793ea64336 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -206,7 +206,7 @@ public class DeviceController extends BaseController { DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); Device device = checkDeviceId(deviceId, Operation.DELETE); try { - tbDeviceService.deleteDevice(device, getCurrentUser()).get(); + tbDeviceService.delete(device, getCurrentUser()).get(); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 8a01e9ef02..5d9737db23 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -164,7 +164,7 @@ public class EdgeController extends BaseController { accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edge.getId(), edge); - return tbEdgeService.saveEdge(edge, edgeTemplateRootRuleChain, getCurrentUser()); + return tbEdgeService.save(edge, edgeTemplateRootRuleChain, getCurrentUser()); } @ApiOperation(value = "Delete edge (deleteEdge)", @@ -177,7 +177,7 @@ public class EdgeController extends BaseController { checkParameter(EDGE_ID, strEdgeId); EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); Edge edge = checkEdgeId(edgeId, Operation.DELETE); - tbEdgeService.deleteEdge(edge, getCurrentUser()); + tbEdgeService.delete(edge, getCurrentUser()); } @ApiOperation(value = "Get Tenant Edges (getEdges)", diff --git a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java index 834eeb555d..e9999d2dc1 100644 --- a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java @@ -66,7 +66,7 @@ public class AssetBulkImportService extends AbstractBulkImportService { @Override @SneakyThrows protected Asset saveEntity(SecurityUser user, Asset entity, Map fields) { - return tbAssetService.saveAsset(entity, user); + return tbAssetService.save(entity, user); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java index 038dcadfc8..fd55e9b321 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java @@ -76,7 +76,7 @@ public class EdgeBulkImportService extends AbstractBulkImportService { @Override protected Edge saveEntity(SecurityUser user, Edge entity, Map fields) { RuleChain edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(user.getTenantId()); - return tbEdgeService.saveEdge(entity, edgeTemplateRootRuleChain, user); + return tbEdgeService.save(entity, edgeTemplateRootRuleChain, user); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 2cd1ae1acc..1f32063299 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -67,14 +67,21 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, EntityId originatorId, + public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, List relatedEdgeIds, - SecurityUser user, - String body, Object... additionalInfo) { - EntityId entityIdForLogEntityAction = originatorId != null ? originatorId : entityId; - logEntityAction(tenantId, entityIdForLogEntityAction, entity, customerId, actionType, user, additionalInfo); - sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); + SecurityUser user, Object... additionalInfo) { + logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); + sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds); + } + + public void notifyDeleteEntityAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, + CustomerId customerId, ActionType actionType, + List relatedEdgeIds, + SecurityUser user, + String body, Object... additionalInfo) { + logEntityAction(tenantId, originatorId, entity, customerId, actionType, user, additionalInfo); + sendAlarmDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); } @Override @@ -127,7 +134,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS gatewayNotificationsService.onDeviceDeleted(device); tbClusterService.onDeviceDeleted(device, null); - notifyDeleteEntity(tenantId, deviceId, device, customerId, null, ActionType.DELETED, relatedEdgeIds, user,null, additionalInfo); + notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user,null, additionalInfo); } @Override @@ -221,8 +228,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } } - protected void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, - List edgeIds, String body) { + protected void sendAlarmDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, + List edgeIds, String body) { try { sendDeleteNotificationMsg(tenantId, entityId, edgeIds, body); } catch (Exception e) { @@ -230,6 +237,15 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } } + protected void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, + List edgeIds) { + try { + sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null); + } catch (Exception e) { + log.warn("Failed to push delete " + entity.getClass().getName() + " msg to core: {}", entity, e); + } + } + private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List edgeIds, String body) { if (edgeIds != null && !edgeIds.isEmpty()) { for (EdgeId edgeId : edgeIds) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 1e0bcf1124..93a8b66749 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -43,9 +43,15 @@ public interface TbNotificationEntityService { CustomerId customerId, ActionType actionType, SecurityUser user, Object... additionalInfo); - void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, EntityId originatorId, CustomerId customerId, - ActionType actionType, List relatedEdgeIds, SecurityUser user, - String body, Object... additionalInfo); + void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, + CustomerId customerId, ActionType actionType, + List relatedEdgeIds, + SecurityUser user, Object... additionalInfo); + + void notifyDeleteEntityAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, + CustomerId customerId, ActionType actionType, + List relatedEdgeIds, + SecurityUser user, String body, Object... additionalInfo); void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, CustomerId customerId, E entity, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 809b8b4e8c..44f84a5e3b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -77,10 +77,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException { + public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { try { List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteEntity(user.getTenantId(), alarm.getId(), alarm, alarm.getOriginator(), user.getCustomerId(), + notificationEntityService.notifyDeleteEntityAlarm(user.getTenantId(), alarm.getId(), alarm, alarm.getOriginator(), user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm)); return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 85bff96d47..7a6d7f6a81 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -27,5 +27,5 @@ public interface TbAlarmService { void clear(Alarm alarm, SecurityUser user) throws ThingsboardException; - Boolean deleteAlarm(Alarm alarm, SecurityUser user) throws ThingsboardException; + Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index e44e405273..5d1556fd7d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -41,7 +41,7 @@ import java.util.List; public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService { @Override - public Asset saveAsset(Asset asset, SecurityUser user) throws ThingsboardException { + public Asset save(Asset asset, SecurityUser user) throws ThingsboardException { ActionType actionType = asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED; TenantId tenantId = asset.getTenantId(); try { @@ -55,13 +55,13 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb } @Override - public ListenableFuture deleteAsset(Asset asset, SecurityUser user) throws ThingsboardException { + public ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException { TenantId tenantId = asset.getTenantId(); AssetId assetId = asset.getId(); try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId); assetService.deleteAsset(tenantId, assetId); - notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, null, asset.getCustomerId(), ActionType.DELETED, + notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, null, asset.toString()); return removeAlarmsByEntityId(tenantId, assetId); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java index ccbd9e715e..3ffb03cb7b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java @@ -26,9 +26,9 @@ import org.thingsboard.server.service.security.model.SecurityUser; public interface TbAssetService { - Asset saveAsset(Asset asset, SecurityUser user) throws ThingsboardException; + Asset save(Asset asset, SecurityUser user) throws ThingsboardException; - ListenableFuture deleteAsset (Asset asset, SecurityUser user) throws ThingsboardException; + ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException; Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index b3abdd1fc6..af27daa5db 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -61,7 +61,7 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, customerId); customerService.deleteCustomer(tenantId, customerId); - notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, null, customerId, + notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, customerId, ActionType.DELETED, relatedEdgeIds, user, null); tbClusterService.broadcastEntityStateChangeEvent(tenantId, customerId, ComponentLifecycleEvent.DELETED); } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index a9c6e7dde5..5ea27f9edc 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -36,7 +36,6 @@ import org.thingsboard.server.service.security.model.SecurityUser; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.UUID; @Service @TbCoreComponent @@ -65,7 +64,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement try { List relatedEdgeIds = findRelatedEdgeIds(tenantId, dashboardId); dashboardService.deleteDashboard(tenantId, dashboardId); - notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null, user.getCustomerId(), + notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, null); } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, @@ -125,17 +124,10 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard updateDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + public Dashboard updateDashboardCustomers(Dashboard dashboard, Set customerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; TenantId tenantId = user.getTenantId(); try { - Set customerIds = new HashSet<>(); - if (strCustomerIds != null) { - for (String strCustomerId : strCustomerIds) { - customerIds.add(new CustomerId(UUID.fromString(strCustomerId))); - } - } - Set addedCustomerIds = new HashSet<>(); Set removedCustomerIds = new HashSet<>(); for (CustomerId customerId : customerIds) { @@ -179,20 +171,10 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard addDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + public Dashboard addDashboardCustomers(Dashboard dashboard, Set customerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; TenantId tenantId = user.getTenantId(); try { - Set customerIds = new HashSet<>(); - if (strCustomerIds != null) { - for (String strCustomerId : strCustomerIds) { - CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); - if (!dashboard.isAssignedToCustomer(customerId)) { - customerIds.add(customerId); - } - } - } - if (customerIds.isEmpty()) { return dashboard; } else { @@ -213,21 +195,11 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement } @Override - public Dashboard removeDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException { + public Dashboard removeDashboardCustomers(Dashboard dashboard, Set customerIds, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; TenantId tenantId = user.getTenantId(); try { - Set customerIds = new HashSet<>(); - if (strCustomerIds != null) { - for (String strCustomerId : strCustomerIds) { - CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); - if (dashboard.isAssignedToCustomer(customerId)) { - customerIds.add(customerId); - } - } - } - - if (customerIds.isEmpty()) { + if (customerIds.isEmpty()) { return dashboard; } else { Dashboard savedDashboard = null; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java index 2930b1c10d..84dba247ff 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/TbDashboardService.java @@ -19,11 +19,13 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import org.thingsboard.server.service.security.model.SecurityUser; +import java.util.Set; + public interface TbDashboardService extends SimpleTbEntityService { Dashboard assignDashboardToCustomer(DashboardId dashboardId, Customer customer, SecurityUser user) throws ThingsboardException; @@ -32,11 +34,11 @@ public interface TbDashboardService extends SimpleTbEntityService { Dashboard unassignDashboardFromPublicCustomer(Dashboard dashboard, SecurityUser user) throws ThingsboardException; - Dashboard updateDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + Dashboard updateDashboardCustomers(Dashboard dashboard, Set customerIds, SecurityUser user) throws ThingsboardException; - Dashboard addDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + Dashboard addDashboardCustomers(Dashboard dashboard, Set customerIds, SecurityUser user) throws ThingsboardException; - Dashboard removeDashboardCustomers(Dashboard dashboard, String[] strCustomerIds, SecurityUser user) throws ThingsboardException; + Dashboard removeDashboardCustomers(Dashboard dashboard, Set customerIds, SecurityUser user) throws ThingsboardException; Dashboard asignDashboardToEdge(DashboardId dashboardId, Edge edge, SecurityUser user) throws ThingsboardException; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java index 1bed17f941..08e3a6f4cd 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java @@ -80,7 +80,7 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T } @Override - public ListenableFuture deleteDevice(Device device, SecurityUser user) throws ThingsboardException { + public ListenableFuture delete(Device device, SecurityUser user) throws ThingsboardException { TenantId tenantId = device.getTenantId(); DeviceId deviceId = device.getId(); try { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java index 16fd0c7448..74e0bcfbe0 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java @@ -35,7 +35,7 @@ public interface TbDeviceService { Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException; - ListenableFuture deleteDevice(Device device, SecurityUser user) throws ThingsboardException; + ListenableFuture delete(Device device, SecurityUser user) throws ThingsboardException; Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java index 93487ac5cd..5547c63375 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java @@ -39,7 +39,7 @@ import org.thingsboard.server.service.security.model.SecurityUser; public class DefaultTbEdgeService extends AbstractTbEntityService implements TbEdgeService { @Override - public Edge saveEdge(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException { + public Edge save(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException { ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED; TenantId tenantId = edge.getTenantId(); try { @@ -62,7 +62,7 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE } @Override - public void deleteEdge(Edge edge, SecurityUser user) throws ThingsboardException { + public void delete(Edge edge, SecurityUser user) throws ThingsboardException { ActionType actionType = ActionType.DELETED; EdgeId edgeId = edge.getId(); TenantId tenantId = edge.getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java index 5ed27fbbb3..3b4fc28283 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java @@ -25,9 +25,9 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.service.security.model.SecurityUser; public interface TbEdgeService { - Edge saveEdge(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException; + Edge save(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException; - void deleteEdge(Edge edge, SecurityUser user) throws ThingsboardException; + void delete(Edge edge, SecurityUser user) throws ThingsboardException; Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException; From c61a50afe5ea6a94b46699d2e32f0023cd8a52ba Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 17 May 2022 23:45:07 +0300 Subject: [PATCH 42/58] refactoring: - dashboard comments3 --- .../entitiy/DefaultTbNotificationEntityService.java | 12 ++++++------ .../service/entitiy/TbNotificationEntityService.java | 8 ++++---- .../service/entitiy/alarm/DefaultTbAlarmService.java | 2 +- .../service/entitiy/asset/DefaultTbAssetService.java | 4 ++-- .../entitiy/customer/DefaultTbCustomerService.java | 5 +++-- .../entitiy/dashboard/DefaultTbDashboardService.java | 2 +- .../service/entitiy/edge/DefaultTbEdgeService.java | 4 ++-- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 1f32063299..e421677e84 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -75,11 +75,11 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds); } - public void notifyDeleteEntityAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, - CustomerId customerId, ActionType actionType, - List relatedEdgeIds, - SecurityUser user, - String body, Object... additionalInfo) { + public void notifyDeleteAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, + CustomerId customerId, ActionType actionType, + List relatedEdgeIds, + SecurityUser user, + String body, Object... additionalInfo) { logEntityAction(tenantId, originatorId, entity, customerId, actionType, user, additionalInfo); sendAlarmDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); } @@ -134,7 +134,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS gatewayNotificationsService.onDeviceDeleted(device); tbClusterService.onDeviceDeleted(device, null); - notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user,null, additionalInfo); + notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user, additionalInfo); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 93a8b66749..ec8717ef7b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -48,10 +48,10 @@ public interface TbNotificationEntityService { List relatedEdgeIds, SecurityUser user, Object... additionalInfo); - void notifyDeleteEntityAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, - CustomerId customerId, ActionType actionType, - List relatedEdgeIds, - SecurityUser user, String body, Object... additionalInfo); + void notifyDeleteAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, + CustomerId customerId, ActionType actionType, + List relatedEdgeIds, + SecurityUser user, String body, Object... additionalInfo); void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, CustomerId customerId, E entity, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 44f84a5e3b..bcf0215bac 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -80,7 +80,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { try { List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteEntityAlarm(user.getTenantId(), alarm.getId(), alarm, alarm.getOriginator(), user.getCustomerId(), + notificationEntityService.notifyDeleteAlarm(user.getTenantId(), alarm.getId(), alarm, alarm.getOriginator(), user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm)); return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index 5d1556fd7d..4be68b75f9 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -62,12 +62,12 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb List relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId); assetService.deleteAsset(tenantId, assetId); notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, - relatedEdgeIds, user, null, asset.toString()); + relatedEdgeIds, user, assetId.toString()); return removeAlarmsByEntityId(tenantId, assetId); } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, - ActionType.DELETED, user, e, asset.toString()); + ActionType.DELETED, user, e, assetId.toString()); throw handleException(e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index af27daa5db..8f13b10cc5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -62,10 +62,11 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements List relatedEdgeIds = findRelatedEdgeIds(tenantId, customerId); customerService.deleteCustomer(tenantId, customerId); notificationEntityService.notifyDeleteEntity(tenantId, customerId, customer, customerId, - ActionType.DELETED, relatedEdgeIds, user, null); + ActionType.DELETED, relatedEdgeIds, user, customerId.toString()); tbClusterService.broadcastEntityStateChangeEvent(tenantId, customerId, ComponentLifecycleEvent.DELETED); } catch (Exception e) { - notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null, ActionType.DELETED, user, e); + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null, + ActionType.DELETED, user, e, customerId.toString()); throw handleException(e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index 5ea27f9edc..a1bf4baf6b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -65,7 +65,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement List relatedEdgeIds = findRelatedEdgeIds(tenantId, dashboardId); dashboardService.deleteDashboard(tenantId, dashboardId); notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, user.getCustomerId(), - ActionType.DELETED, relatedEdgeIds, user, null); + ActionType.DELETED, relatedEdgeIds, user, dashboardId.toString()); } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DASHBOARD), null, null, ActionType.DELETED, user, e, dashboardId.toString()); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java index 5547c63375..dca6869cb9 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java @@ -69,9 +69,9 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE try { edgeService.deleteEdge(tenantId, edgeId); notificationEntityService.notifyEdge(tenantId, edgeId, edge.getCustomerId(), edge, actionType, user, edgeId.toString()); - } catch (Exception e) { - notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e); + notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, + user, e, edgeId.toString()); throw handleException(e); } } From 647012c2d4bb848365d255fd8a7dcfbe2d9c05cf Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 18 May 2022 11:14:31 +0300 Subject: [PATCH 43/58] refactoring: - dashboard comments4 --- .../DefaultTbNotificationEntityService.java | 14 +++++++------- .../entitiy/TbNotificationEntityService.java | 2 +- .../entitiy/alarm/DefaultTbAlarmService.java | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index e421677e84..62b020ac32 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -75,13 +75,13 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds); } - public void notifyDeleteAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, - CustomerId customerId, ActionType actionType, - List relatedEdgeIds, - SecurityUser user, - String body, Object... additionalInfo) { - logEntityAction(tenantId, originatorId, entity, customerId, actionType, user, additionalInfo); - sendAlarmDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds, body); + public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, + CustomerId customerId, ActionType actionType, + List relatedEdgeIds, + SecurityUser user, + String body, Object... additionalInfo) { + logEntityAction(tenantId, originatorId, alarm, customerId, actionType, user, additionalInfo); + sendAlarmDeleteNotificationMsg(tenantId, alarm.getId(), alarm, relatedEdgeIds, body); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index ec8717ef7b..5ac8bbcfbf 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -48,7 +48,7 @@ public interface TbNotificationEntityService { List relatedEdgeIds, SecurityUser user, Object... additionalInfo); - void notifyDeleteAlarm(TenantId tenantId, I entityId, E entity, EntityId originatorId, + void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId, ActionType actionType, List relatedEdgeIds, SecurityUser user, String body, Object... additionalInfo); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index bcf0215bac..f00bd06de3 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -80,7 +80,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { try { List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteAlarm(user.getTenantId(), alarm.getId(), alarm, alarm.getOriginator(), user.getCustomerId(), + notificationEntityService.notifyDeleteAlarm(user.getTenantId(), alarm, alarm.getOriginator(), user.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm)); return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { From 7f31069285722b3f630bf873fff1a240fd05e4ad Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 18 May 2022 13:51:51 +0200 Subject: [PATCH 44/58] added loging and refactored --- .../3.3.4/schema_update_device_profile.sql | 20 +++++++++---------- .../entitiy/queue/DefaultTbQueueService.java | 12 ++++++----- .../DefaultTbRuleEngineConsumerService.java | 3 ++- .../common/data/queue/ProcessingStrategy.java | 2 +- ...leEngineQueueAckStrategyConfiguration.java | 1 + .../TbRuleEngineQueueConfiguration.java | 1 + ...ngineQueueSubmitStrategyConfiguration.java | 1 + .../ThingsboardMqttTransportApplication.java | 4 ---- 8 files changed, 23 insertions(+), 21 deletions(-) diff --git a/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql b/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql index 5f739e3a98..e0b0cc7f1a 100644 --- a/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql +++ b/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql @@ -17,16 +17,6 @@ ALTER TABLE device_profile ADD COLUMN IF NOT EXISTS default_queue_id uuid; -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; -$$; - DO $$ BEGIN @@ -45,5 +35,15 @@ $$ 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; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java index 60788ef02b..38bc7be474 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java @@ -79,14 +79,14 @@ public class DefaultTbQueueService implements TbQueueService { public void deleteQueue(TenantId tenantId, QueueId queueId) { Queue queue = queueService.findQueueById(tenantId, queueId); queueService.deleteQueue(tenantId, queueId); - onQueueDeleted(tenantId, queue); + onQueueDeleted(queue); } @Override public void deleteQueueByQueueName(TenantId tenantId, String queueName) { Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, queueName); queueService.deleteQueue(tenantId, queue.getId()); - onQueueDeleted(tenantId, queue); + onQueueDeleted(queue); } private void onQueueCreated(Queue queue) { @@ -123,8 +123,10 @@ public class DefaultTbQueueService implements TbQueueService { } await(); for (int i = currentPartitions; i < oldPartitions; i++) { + String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); + log.info("Removed partition [{}]", fullTopicName); tbQueueAdmin.deleteTopic( - new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); + fullTopicName); } } } else if (!oldQueue.equals(queue) && tbClusterService != null) { @@ -132,7 +134,7 @@ public class DefaultTbQueueService implements TbQueueService { } } - private void onQueueDeleted(TenantId tenantId, Queue queue) { + private void onQueueDeleted(Queue queue) { if (tbClusterService != null) { tbClusterService.onQueueDelete(queue); await(); @@ -141,7 +143,7 @@ public class DefaultTbQueueService implements TbQueueService { if (tbQueueAdmin != null) { for (int i = 0; i < queue.getPartitions(); i++) { String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); - log.debug("Deleting queue [{}]", fullTopicName); + log.info("Deleting queue [{}]", fullTopicName); try { tbQueueAdmin.deleteTopic(fullTopicName); } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 1fb03a2c47..2108b32992 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -133,7 +133,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< this.statsFactory = statsFactory; this.serviceInfoProvider = serviceInfoProvider; this.queueService = queueService; -// this.tenantId = actorContext.getServiceInfoProvider().getIsolatedTenant().orElse(TenantId.SYS_TENANT_ID); } @PostConstruct @@ -406,6 +405,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } private synchronized void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { + log.info("Received queue update msg: [{}]", queueUpdateMsg); String queueName = queueUpdateMsg.getQueueName(); TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())); @@ -439,6 +439,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } private void deleteQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { + log.info("Received queue delete msg: [{}]", queueDeleteMsg); TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java b/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java index 8a315f14ad..3278aadb69 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/queue/ProcessingStrategy.java @@ -24,4 +24,4 @@ public class ProcessingStrategy { private double failurePercentage; private long pauseBetweenRetries; private long maxPauseBetweenRetries; -} \ No newline at end of file +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueAckStrategyConfiguration.java b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueAckStrategyConfiguration.java index 45ce5f8547..da46b94ba4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueAckStrategyConfiguration.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueAckStrategyConfiguration.java @@ -18,6 +18,7 @@ package org.thingsboard.server.queue.settings; import lombok.Data; @Data +@Deprecated public class TbRuleEngineQueueAckStrategyConfiguration { private String type; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueConfiguration.java b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueConfiguration.java index 7732854180..b01fc50e00 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueConfiguration.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueConfiguration.java @@ -18,6 +18,7 @@ package org.thingsboard.server.queue.settings; import lombok.Data; @Data +@Deprecated public class TbRuleEngineQueueConfiguration { private String name; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueSubmitStrategyConfiguration.java b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueSubmitStrategyConfiguration.java index 97c489ffaa..85c6ff43d7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueSubmitStrategyConfiguration.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbRuleEngineQueueSubmitStrategyConfiguration.java @@ -18,6 +18,7 @@ package org.thingsboard.server.queue.settings; import lombok.Data; @Data +@Deprecated public class TbRuleEngineQueueSubmitStrategyConfiguration { private String type; diff --git a/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java b/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java index 1f64be1efe..f97ca22255 100644 --- a/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java +++ b/transport/mqtt/src/main/java/org/thingsboard/server/mqtt/ThingsboardMqttTransportApplication.java @@ -18,12 +18,8 @@ package org.thingsboard.server.mqtt; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; -import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; import java.util.Arrays; From 9e70cb362d837239ac3a063408f559fd6415a74b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 18 May 2022 15:56:46 +0300 Subject: [PATCH 45/58] refactoring: - dashboard delete remove generic --- .../entitiy/DefaultTbNotificationEntityService.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 62b020ac32..63ccd2b7a2 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -81,7 +81,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS SecurityUser user, String body, Object... additionalInfo) { logEntityAction(tenantId, originatorId, alarm, customerId, actionType, user, additionalInfo); - sendAlarmDeleteNotificationMsg(tenantId, alarm.getId(), alarm, relatedEdgeIds, body); + sendAlarmDeleteNotificationMsg(tenantId, alarm, relatedEdgeIds, body); } @Override @@ -228,12 +228,11 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } } - protected void sendAlarmDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, - List edgeIds, String body) { + protected void sendAlarmDeleteNotificationMsg(TenantId tenantId, Alarm alarm, List edgeIds, String body) { try { - sendDeleteNotificationMsg(tenantId, entityId, edgeIds, body); + sendDeleteNotificationMsg(tenantId, alarm.getId(), edgeIds, body); } catch (Exception e) { - log.warn("Failed to push delete " + entity.getClass().getName() + " msg to core: {}", entity, e); + log.warn("Failed to push delete msg to core: {}", alarm, e); } } @@ -242,7 +241,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS try { sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null); } catch (Exception e) { - log.warn("Failed to push delete " + entity.getClass().getName() + " msg to core: {}", entity, e); + log.warn("Failed to push delete msg to core: {}", entity, e); } } From 1d6b9a5cbdc05c514787e6c6d795dc66549fcb73 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 18 May 2022 16:43:01 +0300 Subject: [PATCH 46/58] Version control executor --- common/version-control/pom.xml | 27 ++++ .../sync/vc/DefaultGitRepositoryService.java | 1 - .../version-control/src/main/proto/vc.proto | 71 +++++++++ msa/pom.xml | 1 + msa/vc-executor/pom.xml | 136 ++++++++++++++++++ msa/vc-executor/src/main/conf/logback.xml | 43 ++++++ .../src/main/conf/tb-vc-executor.conf | 22 +++ ...oardVersionControlExecutorApplication.java | 47 ++++++ .../src/main/resources/logback.xml | 34 +++++ .../src/main/resources/tb-vc-executor.yml | 27 ++++ 10 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 common/version-control/src/main/proto/vc.proto create mode 100644 msa/vc-executor/pom.xml create mode 100644 msa/vc-executor/src/main/conf/logback.xml create mode 100644 msa/vc-executor/src/main/conf/tb-vc-executor.conf create mode 100644 msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java create mode 100644 msa/vc-executor/src/main/resources/logback.xml create mode 100644 msa/vc-executor/src/main/resources/tb-vc-executor.yml diff --git a/common/version-control/pom.xml b/common/version-control/pom.xml index f29b7db81a..164640fe73 100644 --- a/common/version-control/pom.xml +++ b/common/version-control/pom.xml @@ -86,6 +86,21 @@ org.eclipse.jgit org.eclipse.jgit + + io.grpc + grpc-netty-shaded + provided + + + io.grpc + grpc-protobuf + provided + + + io.grpc + grpc-stub + provided + org.springframework.boot spring-boot-starter-test @@ -109,7 +124,19 @@ + + org.xolstice.maven.plugins + protobuf-maven-plugin + + + + thingsboard-repo-deploy + ThingsBoard Repo Deployment + https://repo.thingsboard.io/artifactory/libs-release-public + + + diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java index d22fcf5d94..c93b4ae76d 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java @@ -226,7 +226,6 @@ public class DefaultGitRepositoryService implements GitRepositoryService { } } - private EntityVersion toVersion(GitRepository.Commit commit) { return new EntityVersion(commit.getId(), commit.getMessage()); } diff --git a/common/version-control/src/main/proto/vc.proto b/common/version-control/src/main/proto/vc.proto new file mode 100644 index 0000000000..e8c7e09384 --- /dev/null +++ b/common/version-control/src/main/proto/vc.proto @@ -0,0 +1,71 @@ +/** + * 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. + */ +syntax = "proto3"; + +option java_package = "org.thingsboard.server.gen.vc.v1"; +option java_multiple_files = true; +option java_outer_classname = "EdgeProtos"; + +package vc; + +// Interface exported by the ThingsBoard Core. +service TbGitRpcService { + + rpc commit(stream CommitRequestMsg) returns (CommitResponseMsg) {} + +} + + +/** + * Data Structures; + */ +message CommitRequestMsg { + string txId = 1; + PrepareMsg prepareMsg = 2; + AddMsg addMsg = 3; + DeleteMsg deleteMsg = 4; + PushMsg pushMsg = 5; + AbortMsg abortMsg = 6; +} + +message CommitResponseMsg { + string id = 1; + string name = 2; + int32 added = 3; + int32 modified = 4; + int32 removed = 5; +} + +message PrepareMsg { + string tenantId = 1; + string commitMsg = 2; + string branchName = 3; +} + +message AddMsg { + string relativePath = 1; + string entityDataJson = 2; +} + +message DeleteMsg { + string relativePath = 1; +} + +message PushMsg { +} + +message AbortMsg { +} \ No newline at end of file diff --git a/msa/pom.xml b/msa/pom.xml index 106f2be2a3..888291502b 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -40,6 +40,7 @@ tb + vc-executor js-executor web-ui tb-node diff --git a/msa/vc-executor/pom.xml b/msa/vc-executor/pom.xml new file mode 100644 index 0000000000..7e4df36117 --- /dev/null +++ b/msa/vc-executor/pom.xml @@ -0,0 +1,136 @@ + + + 4.0.0 + + + org.thingsboard + 3.4.0-SNAPSHOT + msa + + org.thingsboard.msa + vc-executor + + ThingsBoard Version Control Executor + https://thingsboard.io + Project for ThingsBoard version control microservice + + + UTF-8 + ${basedir}/../.. + java + false + process-resources + package + tb-mqtt-transport + false + ${project.build.directory}/windows + ThingsBoard Version Control Executor Service + org.thingsboard.server.vc.ThingsboardVersionControlExecutorApplication + + + + + org.thingsboard.common + version-control + + + org.springframework.boot + spring-boot-starter-web + + + io.grpc + grpc-netty-shaded + + + io.grpc + grpc-protobuf + + + io.grpc + grpc-stub + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.awaitility + awaitility + test + + + + + ${pkg.name}-${project.version} + + + ${project.basedir}/src/main/resources + + + + + org.apache.maven.plugins + maven-resources-plugin + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + org.thingsboard + gradle-maven-plugin + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.apache.maven.plugins + maven-install-plugin + + + + + + jenkins + Jenkins Repository + https://repo.jenkins-ci.org/releases + + false + + + + + + diff --git a/msa/vc-executor/src/main/conf/logback.xml b/msa/vc-executor/src/main/conf/logback.xml new file mode 100644 index 0000000000..d62cf2b3f5 --- /dev/null +++ b/msa/vc-executor/src/main/conf/logback.xml @@ -0,0 +1,43 @@ + + + + + + + ${pkg.logFolder}/${pkg.name}.log + + ${pkg.logFolder}/${pkg.name}.%d{yyyy-MM-dd}.%i.log + 100MB + 30 + 3GB + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + diff --git a/msa/vc-executor/src/main/conf/tb-vc-executor.conf b/msa/vc-executor/src/main/conf/tb-vc-executor.conf new file mode 100644 index 0000000000..83287286bb --- /dev/null +++ b/msa/vc-executor/src/main/conf/tb-vc-executor.conf @@ -0,0 +1,22 @@ +# +# 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. +# + +export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=@pkg.logFolder@/gc.log:time,uptime,level,tags:filecount=10,filesize=10M" +export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError" +export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" +export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10" +export LOG_FILENAME=${pkg.name}.out +export LOADER_PATH=${pkg.installFolder}/conf diff --git a/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java b/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java new file mode 100644 index 0000000000..2724a566ee --- /dev/null +++ b/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java @@ -0,0 +1,47 @@ +package org.thingsboard.server.vc; /** + * 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. + */ + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.Arrays; + +@SpringBootConfiguration +@EnableAsync +@EnableScheduling +@ComponentScan({"org.thingsboard.server.vc", "org.thingsboard.server.common", "org.thingsboard.server.sync.vc"}) +public class ThingsboardVersionControlExecutorApplication { + + private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; + private static final String DEFAULT_SPRING_CONFIG_PARAM = SPRING_CONFIG_NAME_KEY + "=" + "tb-vc-executor"; + + public static void main(String[] args) { + SpringApplication.run(ThingsboardVersionControlExecutorApplication.class, updateArguments(args)); + } + + private static String[] updateArguments(String[] args) { + if (Arrays.stream(args).noneMatch(arg -> arg.startsWith(SPRING_CONFIG_NAME_KEY))) { + String[] modifiedArgs = new String[args.length + 1]; + System.arraycopy(args, 0, modifiedArgs, 0, args.length); + modifiedArgs[args.length] = DEFAULT_SPRING_CONFIG_PARAM; + return modifiedArgs; + } + return args; + } +} diff --git a/msa/vc-executor/src/main/resources/logback.xml b/msa/vc-executor/src/main/resources/logback.xml new file mode 100644 index 0000000000..2834934ee0 --- /dev/null +++ b/msa/vc-executor/src/main/resources/logback.xml @@ -0,0 +1,34 @@ + + + + + + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml new file mode 100644 index 0000000000..1de47e2750 --- /dev/null +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -0,0 +1,27 @@ +# +# 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. +# + +# If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" +# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" + +server: + # Server bind address (has no effect if web-environment is disabled). + address: "${HTTP_BIND_ADDRESS:0.0.0.0}" + # Server bind port (has no effect if web-environment is disabled). + port: "${HTTP_BIND_PORT:8080}" + From 92117d12809f8c052c4211e3ef6678fc133939c7 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 18 May 2022 22:23:20 +0200 Subject: [PATCH 47/58] used scheduler instead of thread sleep --- .../entitiy/AbstractTbEntityService.java | 7 +- .../entitiy/queue/DefaultTbQueueService.java | 69 ++++++++----------- .../DefaultTbTenantProfileService.java | 4 +- .../dao/device/DeviceProfileServiceImpl.java | 1 - 4 files changed, 35 insertions(+), 46 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java index e2ccc1f3d2..74529d8c15 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java @@ -15,14 +15,12 @@ */ package org.thingsboard.server.service.entitiy; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.User; @@ -50,6 +48,7 @@ import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; @@ -69,8 +68,6 @@ public abstract class AbstractTbEntityService { protected static final int DEFAULT_PAGE_SIZE = 1000; - private static final ObjectMapper json = new ObjectMapper(); - @Value("${server.log_controller_error_stack_trace}") @Getter private boolean logControllerErrorStackTrace; @@ -106,6 +103,8 @@ public abstract class AbstractTbEntityService { protected RuleChainService ruleChainService; @Autowired protected EdgeNotificationService edgeNotificationService; + @Autowired + protected QueueService queueService; protected ListenableFuture removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) { ListenableFuture> alarmsFuture = diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java index 38bc7be474..6a5778a474 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.entitiy.queue; import lombok.AllArgsConstructor; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.cluster.TbClusterService; @@ -30,27 +29,30 @@ import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.device.DeviceProfileService; -import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @Service @TbCoreComponent @AllArgsConstructor -public class DefaultTbQueueService implements TbQueueService { +public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService { private static final String MAIN = "Main"; + private static final long DELETE_DELAY = 30; - private final QueueService queueService; private final TbClusterService tbClusterService; private final TbQueueAdmin tbQueueAdmin; private final DeviceProfileService deviceProfileService; + private final SchedulerComponent scheduler; @Override public Queue saveQueue(Queue queue) { @@ -90,57 +92,50 @@ public class DefaultTbQueueService implements TbQueueService { } private void onQueueCreated(Queue queue) { - if (tbQueueAdmin != null) { - for (int i = 0; i < queue.getPartitions(); i++) { - tbQueueAdmin.createTopicIfNotExists( - new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); - } + for (int i = 0; i < queue.getPartitions(); i++) { + tbQueueAdmin.createTopicIfNotExists( + new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } - if (tbClusterService != null) { - tbClusterService.onQueueChange(queue); - } + tbClusterService.onQueueChange(queue); } private void onQueueUpdated(Queue queue, Queue oldQueue) { int oldPartitions = oldQueue.getPartitions(); int currentPartitions = queue.getPartitions(); - if (currentPartitions != oldPartitions && tbQueueAdmin != null) { + if (currentPartitions != oldPartitions) { if (currentPartitions > oldPartitions) { log.info("Added [{}] new partitions to [{}] queue", currentPartitions - oldPartitions, queue.getName()); for (int i = oldPartitions; i < currentPartitions; i++) { tbQueueAdmin.createTopicIfNotExists( new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName()); } - if (tbClusterService != null) { - tbClusterService.onQueueChange(queue); - } + tbClusterService.onQueueChange(queue); } else { log.info("Removed [{}] partitions from [{}] queue", oldPartitions - currentPartitions, queue.getName()); - if (tbClusterService != null) { - tbClusterService.onQueueChange(queue); - } - await(); - for (int i = currentPartitions; i < oldPartitions; i++) { - String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); - log.info("Removed partition [{}]", fullTopicName); - tbQueueAdmin.deleteTopic( - fullTopicName); - } + tbClusterService.onQueueChange(queue); + + scheduler.schedule(() -> { + for (int i = currentPartitions; i < oldPartitions; i++) { + String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); + log.info("Removed partition [{}]", fullTopicName); + tbQueueAdmin.deleteTopic( + fullTopicName); + } + }, DELETE_DELAY, TimeUnit.SECONDS); } - } else if (!oldQueue.equals(queue) && tbClusterService != null) { + } else if (!oldQueue.equals(queue)) { tbClusterService.onQueueChange(queue); } } private void onQueueDeleted(Queue queue) { - if (tbClusterService != null) { - tbClusterService.onQueueDelete(queue); - await(); - } + tbClusterService.onQueueDelete(queue); + // queueStatsService.deleteQueueStatsByQueueId(tenantId, queueId); - if (tbQueueAdmin != null) { + + scheduler.schedule(() -> { for (int i = 0; i < queue.getPartitions(); i++) { String fullTopicName = new TopicPartitionInfo(queue.getTopic(), queue.getTenantId(), i, false).getFullTopicName(); log.info("Deleting queue [{}]", fullTopicName); @@ -150,16 +145,12 @@ public class DefaultTbQueueService implements TbQueueService { log.error("Failed to delete queue [{}]", fullTopicName); } } - } - } - - @SneakyThrows - private void await() { - Thread.sleep(3000); + }, DELETE_DELAY, TimeUnit.SECONDS); } @Override - public void updateQueuesByTenants(List tenantIds, TenantProfile newTenantProfile, TenantProfile oldTenantProfile) { + public void updateQueuesByTenants(List tenantIds, TenantProfile newTenantProfile, TenantProfile + oldTenantProfile) { boolean oldIsolated = oldTenantProfile != null && oldTenantProfile.isIsolatedTbRuleEngine(); boolean newIsolated = newTenantProfile.isIsolatedTbRuleEngine(); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant_profile/DefaultTbTenantProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant_profile/DefaultTbTenantProfileService.java index 23a838e72a..23d9f74b8e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant_profile/DefaultTbTenantProfileService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant_profile/DefaultTbTenantProfileService.java @@ -32,7 +32,7 @@ import java.util.List; @TbCoreComponent @AllArgsConstructor public class DefaultTbTenantProfileService implements TbTenantProfileService { - private final TbQueueService queueService; + private final TbQueueService tbQueueService; private final TenantProfileService tenantProfileService; private final TenantService tenantService; @@ -42,7 +42,7 @@ public class DefaultTbTenantProfileService implements TbTenantProfileService { if (oldTenantProfile != null && savedTenantProfile.isIsolatedTbRuleEngine()) { List tenantIds = tenantService.findTenantIdsByTenantProfileId(savedTenantProfile.getId()); - queueService.updateQueuesByTenants(tenantIds, savedTenantProfile, oldTenantProfile); + tbQueueService.updateQueuesByTenants(tenantIds, savedTenantProfile, oldTenantProfile); } return savedTenantProfile; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index f981aa55e5..04084de987 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; From 4f7c1665663cb8e4c932e50c5d7b9f3405cdda64 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 00:36:26 +0200 Subject: [PATCH 48/58] using repartitionExecutor instead of synchronized --- .../service/queue/DefaultTbRuleEngineConsumerService.java | 6 +++--- .../server/queue/discovery/HashPartitionService.java | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 2108b32992..1844929d35 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -393,10 +393,10 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< tbDeviceRpcService.processRpcResponseFromDevice(response); callback.onSuccess(); } else if (nfMsg.hasQueueUpdateMsg()) { - updateQueue(nfMsg.getQueueUpdateMsg()); + repartitionExecutor.execute(() -> updateQueue(nfMsg.getQueueUpdateMsg())); callback.onSuccess(); } else if (nfMsg.hasQueueDeleteMsg()) { - deleteQueue(nfMsg.getQueueDeleteMsg()); + repartitionExecutor.execute(() -> deleteQueue(nfMsg.getQueueDeleteMsg())); callback.onSuccess(); } else { log.trace("Received notification with missing handler"); @@ -404,7 +404,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } - private synchronized void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { + private void updateQueue(TransportProtos.QueueUpdateMsg queueUpdateMsg) { log.info("Received queue update msg: [{}]", queueUpdateMsg); String queueName = queueUpdateMsg.getQueueName(); TenantId tenantId = new TenantId(new UUID(queueUpdateMsg.getTenantIdMSB(), queueUpdateMsg.getTenantIdLSB())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 92278f7b4a..f9033754ff 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -173,7 +173,6 @@ public class HashPartitionService implements PartitionService { } else { QueueRoutingInfo queueRoutingInfo = queuesById.get(queueId); - //TODO: replace if we can notify CheckPoint rule nodes about queue changes if (queueRoutingInfo == null) { log.debug("Queue was removed but still used in CheckPoint rule node. [{}][{}]", tenantId, entityId); queueKey = getMainQueueKey(serviceType, tenantId); @@ -205,6 +204,8 @@ public class HashPartitionService implements PartitionService { @Override public synchronized void recalculatePartitions(ServiceInfo currentService, List otherServices) { + partitionsInit(); + tbTransportServicesByType.clear(); logServiceInfo(currentService); otherServices.forEach(this::logServiceInfo); From abe127c3faeb92152ee8aac5c7b37a65ca07b7eb Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 01:18:13 +0200 Subject: [PATCH 49/58] fixed checkpoint node --- .../thingsboard/server/controller/QueueController.java | 1 + .../thingsboard/rule/engine/flow/TbCheckpointNode.java | 10 +++++++--- .../engine/flow/TbCheckpointNodeConfiguration.java | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java index 3b7b407b47..9b83aa43fb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java @@ -107,6 +107,7 @@ public class QueueController extends BaseController { checkParameter("queueId", queueIdStr); try { QueueId queueId = new QueueId(UUID.fromString(queueIdStr)); + checkQueueId(queueId, Operation.READ); return checkNotNull(queueService.findQueueById(getTenantId(), queueId)); } catch ( Exception e) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java index 470a774b90..ff69212c67 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java @@ -23,9 +23,12 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.UUID; + @Slf4j @RuleNode( type = ComponentType.FLOW, @@ -38,16 +41,17 @@ import org.thingsboard.server.common.msg.TbMsg; ) public class TbCheckpointNode implements TbNode { - private TbCheckpointNodeConfiguration config; + private QueueId queueId; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class); + TbCheckpointNodeConfiguration config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class); + this.queueId = new QueueId(UUID.fromString(config.getQueueId())); } @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.enqueueForTellNext(msg, config.getQueueId(), TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); + ctx.enqueueForTellNext(msg, queueId, TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java index 0546732874..42bd6342c9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java +++ b/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 public class TbCheckpointNodeConfiguration implements NodeConfiguration { - private QueueId queueId; + private String queueId; @Override public TbCheckpointNodeConfiguration defaultConfiguration() { From fa4a20d711d0d263fbe197eeba15a7a860c1c9b4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 10:04:51 +0200 Subject: [PATCH 50/58] Added resolve by queue name for backward compatibility --- .../server/actors/ActorSystemContext.java | 5 +++++ .../server/actors/ruleChain/DefaultTbContext.java | 12 ++++++++++++ .../server/queue/discovery/HashPartitionService.java | 12 ++++++++++++ .../server/queue/discovery/PartitionService.java | 3 +++ .../org/thingsboard/rule/engine/api/TbContext.java | 3 +++ 5 files changed, 35 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 4059c51a57..500ad60524 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -506,6 +506,11 @@ public class ActorSystemContext { return partitionService.resolve(serviceType, queueId, tenantId, entityId); } + @Deprecated + public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) { + return partitionService.resolve(serviceType, tenantId, entityId, queueName); + } + public String getServiceId() { return serviceInfoProvider.getServiceId(); } diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index ee3f5e15ac..bf643a8967 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -161,6 +161,13 @@ class DefaultTbContext implements TbContext { enqueue(tpi, tbMsg, onFailure, onSuccess); } + @Override + @Deprecated + public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer onFailure) { + TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName); + enqueue(tpi, tbMsg, onFailure, onSuccess); + } + @Override public void enqueue(TbMsg tbMsg, QueueId queueId, Runnable onSuccess, Consumer onFailure) { TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId); @@ -229,6 +236,11 @@ class DefaultTbContext implements TbContext { return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueId, getTenantId(), tbMsg.getOriginator()); } + @Deprecated + private TopicPartitionInfo resolvePartition(TbMsg tbMsg, String queueName) { + return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator()); + } + private TopicPartitionInfo resolvePartition(TbMsg tbMsg) { return resolvePartition(tbMsg, tbMsg.getQueueId()); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index f9033754ff..5a522f9233 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -160,6 +160,18 @@ public class HashPartitionService implements PartitionService { removeTenant(tenantId); } + @Override + @Deprecated + 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); + QueueKey queueKey = new QueueKey(serviceType, queueName, isolatedOrSystemTenantId); + if (!partitionSizesMap.containsKey(queueKey)) { + queueKey = new QueueKey(serviceType, isolatedOrSystemTenantId); + } + return resolve(queueKey, entityId); + } + @Override public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) { return resolve(serviceType, null, tenantId, entityId); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java index 207de90e7b..3844bf02c9 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionService.java @@ -32,6 +32,9 @@ import java.util.UUID; */ public interface PartitionService { + @Deprecated + TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId, String queueName); + TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId); TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index ce66b4fbce..1a817806da 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -142,6 +142,9 @@ public interface TbContext { */ void output(TbMsg msg, String relationType); + @Deprecated + void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer onFailure); + /** * Puts new message to custom queue for processing * From e32e161745a2f05b7d60771f69531d2597875236 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 11:13:31 +0200 Subject: [PATCH 51/58] fixed queue permissions --- .../server/controller/BaseController.java | 13 +++++++++++-- .../permission/TenantAdminPermissions.java | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index b787a85d1b..195ea9a3ee 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -69,8 +69,8 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.OtaPackageId; -import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TbResourceId; @@ -85,9 +85,9 @@ import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rpc.Rpc; -import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; @@ -150,6 +150,7 @@ import java.util.UUID; import static org.thingsboard.server.controller.ControllerConstants.DEFAULT_PAGE_SIZE; import static org.thingsboard.server.controller.ControllerConstants.INCORRECT_TENANT_ID; +import static org.thingsboard.server.controller.UserController.YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION; import static org.thingsboard.server.dao.service.Validator.validateId; @Slf4j @@ -825,6 +826,14 @@ public abstract class BaseController { Queue queue = queueService.findQueueById(getCurrentUser().getTenantId(), queueId); checkNotNull(queue); accessControlService.checkPermission(getCurrentUser(), Resource.QUEUE, operation, queueId, queue); + TenantId tenantId = getTenantId(); + if (queue.getTenantId().isNullUid() && !tenantId.isNullUid()) { + TenantProfile tenantProfile = tenantProfileCache.get(tenantId); + if (tenantProfile.isIsolatedTbRuleEngine()) { + throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION, + ThingsboardErrorCode.PERMISSION_DENIED); + } + } return queue; } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java index bcc6251315..5810c6c4f8 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java @@ -45,7 +45,7 @@ public class TenantAdminPermissions extends AbstractPermissions { put(Resource.OTA_PACKAGE, tenantEntityPermissionChecker); put(Resource.EDGE, tenantEntityPermissionChecker); put(Resource.RPC, tenantEntityPermissionChecker); - put(Resource.QUEUE, tenantEntityPermissionChecker); + put(Resource.QUEUE, queuePermissionChecker); } public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() { @@ -121,4 +121,20 @@ public class TenantAdminPermissions extends AbstractPermissions { } }; + + private static final PermissionChecker queuePermissionChecker = new PermissionChecker() { + + @Override + public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { + if (entity.getTenantId() == null || entity.getTenantId().isNullUid()) { + return operation == Operation.READ; + } + if (!user.getTenantId().equals(entity.getTenantId())) { + return false; + } + return true; + } + + }; + } From b8f2d6ee9c99c6e475b4669125f1bae8f4269126 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 13:09:40 +0200 Subject: [PATCH 52/58] added tenant profile upgrade --- .../install/SqlDatabaseUpgradeService.java | 100 ++++++++++++++---- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 473f3accda..db2352b706 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -35,13 +36,16 @@ 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.RuleNode; +import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; +import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import org.thingsboard.server.service.install.sql.SqlDbHelper; import java.nio.charset.Charset; @@ -55,6 +59,7 @@ import java.sql.SQLException; import java.sql.SQLSyntaxErrorException; import java.sql.SQLWarning; import java.sql.Statement; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -125,6 +130,9 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @Autowired private RuleChainService ruleChainService; + @Autowired + private TenantProfileService tenantProfileService; + @Override public void upgradeDatabase(String fromVersion) throws Exception { switch (fromVersion) { @@ -567,26 +575,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService try { if (!CollectionUtils.isEmpty(queueConfig.getQueues())) { queueConfig.getQueues().forEach(queueSettings -> { - Queue queue = new Queue(); - queue.setTenantId(TenantId.SYS_TENANT_ID); - queue.setName(queueSettings.getName()); - queue.setTopic(queueSettings.getTopic()); - queue.setPollInterval(queueSettings.getPollInterval()); - queue.setPartitions(queueSettings.getPartitions()); - queue.setPackProcessingTimeout(queueSettings.getPackProcessingTimeout()); - SubmitStrategy submitStrategy = new SubmitStrategy(); - submitStrategy.setBatchSize(queueSettings.getSubmitStrategy().getBatchSize()); - submitStrategy.setType(SubmitStrategyType.valueOf(queueSettings.getSubmitStrategy().getType())); - queue.setSubmitStrategy(submitStrategy); - ProcessingStrategy processingStrategy = new ProcessingStrategy(); - processingStrategy.setType(ProcessingStrategyType.valueOf(queueSettings.getProcessingStrategy().getType())); - processingStrategy.setRetries(queueSettings.getProcessingStrategy().getRetries()); - processingStrategy.setFailurePercentage(queueSettings.getProcessingStrategy().getFailurePercentage()); - processingStrategy.setPauseBetweenRetries(queueSettings.getProcessingStrategy().getPauseBetweenRetries()); - processingStrategy.setMaxPauseBetweenRetries(queueSettings.getProcessingStrategy().getMaxPauseBetweenRetries()); - queue.setProcessingStrategy(processingStrategy); - queue.setConsumerPerPartition(queueSettings.isConsumerPerPartition()); - queueService.saveQueue(queue); + queueService.saveQueue(queueConfigToQueue(queueSettings)); }); } else { systemDataLoaderService.createQueues(); @@ -625,6 +614,32 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService pageLink = pageLink.nextPageLink(); } while (pageData.hasNext()); + log.info("Updating tenant profiles..."); + PageLink profilePageLink = new PageLink(100); + PageData profilePageData; + do { + profilePageData = tenantProfileService.findTenantProfiles(TenantId.SYS_TENANT_ID, profilePageLink); + + profilePageData.getData().forEach(profile -> { + try { + List queueConfiguration = profile.getProfileData().getQueueConfiguration(); + if (profile.isIsolatedTbRuleEngine() && (queueConfiguration == null || queueConfiguration.isEmpty())) { + TenantProfileQueueConfiguration mainQueueConfig = getMainQueueConfiguration(); + profile.getProfileData().setQueueConfiguration(Collections.singletonList((mainQueueConfig))); + tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, profile); + List isolatedTenants = tenantService.findTenantIdsByTenantProfileId(profile.getId()); + isolatedTenants.forEach(tenantId -> { + queueService.saveQueue(new Queue(tenantId, mainQueueConfig)); + }); + } + } catch (Exception e) { + } + + }); + profilePageLink = profilePageLink.nextPageLink(); + } while (profilePageData.hasNext()); + + log.info("Updating schema settings..."); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;"); log.info("Schema updated."); @@ -677,4 +692,49 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService } return isOldSchema; } + + private Queue queueConfigToQueue(TbRuleEngineQueueConfiguration queueSettings) { + Queue queue = new Queue(); + queue.setTenantId(TenantId.SYS_TENANT_ID); + queue.setName(queueSettings.getName()); + queue.setTopic(queueSettings.getTopic()); + queue.setPollInterval(queueSettings.getPollInterval()); + queue.setPartitions(queueSettings.getPartitions()); + queue.setPackProcessingTimeout(queueSettings.getPackProcessingTimeout()); + SubmitStrategy submitStrategy = new SubmitStrategy(); + submitStrategy.setBatchSize(queueSettings.getSubmitStrategy().getBatchSize()); + submitStrategy.setType(SubmitStrategyType.valueOf(queueSettings.getSubmitStrategy().getType())); + queue.setSubmitStrategy(submitStrategy); + ProcessingStrategy processingStrategy = new ProcessingStrategy(); + processingStrategy.setType(ProcessingStrategyType.valueOf(queueSettings.getProcessingStrategy().getType())); + processingStrategy.setRetries(queueSettings.getProcessingStrategy().getRetries()); + processingStrategy.setFailurePercentage(queueSettings.getProcessingStrategy().getFailurePercentage()); + processingStrategy.setPauseBetweenRetries(queueSettings.getProcessingStrategy().getPauseBetweenRetries()); + processingStrategy.setMaxPauseBetweenRetries(queueSettings.getProcessingStrategy().getMaxPauseBetweenRetries()); + queue.setProcessingStrategy(processingStrategy); + queue.setConsumerPerPartition(queueSettings.isConsumerPerPartition()); + return queue; + } + + private TenantProfileQueueConfiguration getMainQueueConfiguration() { + 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); + return mainQueueConfiguration; + } } From 38fb68b2001935b90908a19dd9be39bf43f515a5 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 16:14:58 +0200 Subject: [PATCH 53/58] fixed stoping RE consumers --- .../service/queue/DefaultTbRuleEngineConsumerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 1844929d35..8496fa7827 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -75,6 +75,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -268,7 +269,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< final TbRuleEngineSubmitStrategy submitStrategy = getSubmitStrategy(configuration); final TbRuleEngineProcessingStrategy ackStrategy = getAckStrategy(configuration); submitStrategy.init(msgs); - while (!stopped) { + while (!stopped && !consumer.isStopped()) { TbMsgPackProcessingContext ctx = new TbMsgPackProcessingContext(configuration.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); submitStrategy.submitAttempt((id, msg) -> submitExecutor.submit(() -> submitMessage(configuration, stats, ctx, id, msg))); From 10248aa9f64c5d90d2692cf35f7b803b0f11d384 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 19 May 2022 17:49:40 +0300 Subject: [PATCH 54/58] fix of the packge list --- .../server/vc/ThingsboardVersionControlExecutorApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java b/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java index 2724a566ee..d30818110d 100644 --- a/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java +++ b/msa/vc-executor/src/main/java/org/thingsboard/server/vc/ThingsboardVersionControlExecutorApplication.java @@ -25,7 +25,7 @@ import java.util.Arrays; @SpringBootConfiguration @EnableAsync @EnableScheduling -@ComponentScan({"org.thingsboard.server.vc", "org.thingsboard.server.common", "org.thingsboard.server.sync.vc"}) +@ComponentScan({"org.thingsboard.server.vc", "org.thingsboard.server.common", "org.thingsboard.server.service.sync.vc"}) public class ThingsboardVersionControlExecutorApplication { private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; From ee8c9deda98981a18f4555be7fc428ecb5937201 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 19 May 2022 23:55:16 +0200 Subject: [PATCH 55/58] refactoring --- .../DefaultTbLocalSubscriptionService.java | 2 +- .../routing/HashPartitionServiceTest.java | 4 -- common/cluster-api/src/main/proto/queue.proto | 9 --- .../server/common/msg/queue/ServiceQueue.java | 62 ------------------- .../common/msg/queue/ServiceQueueKey.java | 48 -------------- .../DefaultTbServiceInfoProvider.java | 4 -- .../queue/discovery/HashPartitionService.java | 22 +++---- .../event/ClusterTopologyChangeEvent.java | 9 ++- .../src/main/resources/tb-coap-transport.yml | 2 - .../src/main/resources/tb-http-transport.yml | 2 - .../src/main/resources/tb-lwm2m-transport.yml | 2 - .../src/main/resources/tb-mqtt-transport.yml | 1 - .../src/main/resources/tb-snmp-transport.yml | 1 - 13 files changed, 14 insertions(+), 154 deletions(-) delete mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueue.java delete mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java index 84f8c36896..968e15ea4b 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java @@ -76,7 +76,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer private TbApplicationEventListener clusterTopologyChangeListener = new TbApplicationEventListener<>() { @Override protected void onTbApplicationEvent(ClusterTopologyChangeEvent event) { - if (event.getServiceQueueKeys().stream().anyMatch(key -> ServiceType.TB_CORE.equals(key.getServiceType()))) { + if (event.getQueueKeys().stream().anyMatch(key -> ServiceType.TB_CORE.equals(key.getType()))) { /* * If the cluster topology has changed, we need to push all current subscriptions to SubscriptionManagerService again. * Otherwise, the SubscriptionManagerService may "forget" those subscriptions in case of restart. diff --git a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java index c8fb678470..74738c361f 100644 --- a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java @@ -74,8 +74,6 @@ public class HashPartitionServiceTest { ReflectionTestUtils.setField(clusterRoutingService, "hashFunctionName", hashFunctionName); TransportProtos.ServiceInfo currentServer = TransportProtos.ServiceInfo.newBuilder() .setServiceId("tb-core-0") -// .setTenantIdMSB(TenantId.NULL_UUID.getMostSignificantBits()) -// .setTenantIdLSB(TenantId.NULL_UUID.getLeastSignificantBits()) .addAllServiceTypes(Collections.singletonList(ServiceType.TB_CORE.name())) .build(); // when(queueService.resolve(Mockito.any(), Mockito.anyString())).thenAnswer(i -> i.getArguments()[1]); @@ -84,8 +82,6 @@ public class HashPartitionServiceTest { for (int i = 1; i < SERVER_COUNT; i++) { otherServers.add(TransportProtos.ServiceInfo.newBuilder() .setServiceId("tb-rule-" + i) -// .setTenantIdMSB(TenantId.NULL_UUID.getMostSignificantBits()) -// .setTenantIdLSB(TenantId.NULL_UUID.getLeastSignificantBits()) .addAllServiceTypes(Collections.singletonList(ServiceType.TB_CORE.name())) .build()); } diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 32bcfd688d..50f114856f 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -20,21 +20,12 @@ package transport; option java_package = "org.thingsboard.server.gen.transport"; option java_outer_classname = "TransportProtos"; -//message QueueInfo { -// string name = 1; -// string topic = 2; -// int32 partitions = 3; -//} - /** * Service Discovery Data Structures; */ message ServiceInfo { string serviceId = 1; repeated string serviceTypes = 2; -// int64 tenantIdMSB = 3; -// int64 tenantIdLSB = 4; -// repeated QueueInfo ruleEngineQueues = 5; repeated string transports = 6; } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueue.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueue.java deleted file mode 100644 index 76f4202607..0000000000 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueue.java +++ /dev/null @@ -1,62 +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.common.msg.queue; - -import lombok.ToString; - -import java.util.Objects; - -@ToString -public class ServiceQueue { - - public static final String MAIN = "Main"; - - private final ServiceType type; - private final String queue; - - public ServiceQueue(ServiceType type) { - this.type = type; - this.queue = MAIN; - } - - public ServiceQueue(ServiceType type, String queue) { - this.type = type; - this.queue = queue != null ? queue : MAIN; - } - - public ServiceType getType() { - return type; - } - - public String getQueue() { - return queue; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ServiceQueue that = (ServiceQueue) o; - return type == that.type && - queue.equals(that.queue); - } - - @Override - public int hashCode() { - return Objects.hash(type, queue); - } - -} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java deleted file mode 100644 index f47f5ab8b1..0000000000 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceQueueKey.java +++ /dev/null @@ -1,48 +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.common.msg.queue; - -import lombok.Getter; -import lombok.ToString; - -import java.util.Objects; - -@ToString -public class ServiceQueueKey { - @Getter - private final ServiceQueue serviceQueue; - - public ServiceQueueKey(ServiceQueue serviceQueue) { - this.serviceQueue = serviceQueue; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ServiceQueueKey that = (ServiceQueueKey) o; - return serviceQueue.equals(that.serviceQueue); - } - - @Override - public int hashCode() { - return Objects.hash(serviceQueue); - } - - public ServiceType getServiceType() { - return serviceQueue.getType(); - } -} \ No newline at end of file diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java index 78ed1175ba..a3744c3946 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/DefaultTbServiceInfoProvider.java @@ -48,10 +48,6 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { @Value("${service.type:monolith}") private String serviceType; - @Getter - @Value("${service.tenant_id:}") - private String tenantIdStr; - @Autowired private ApplicationContext applicationContext; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 5a522f9233..ccf8b9dd92 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -24,8 +24,6 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.msg.queue.ServiceQueue; -import org.thingsboard.server.common.msg.queue.ServiceQueueKey; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; @@ -260,9 +258,9 @@ public class HashPartitionService implements PartitionService { if (currentOtherServices == null) { currentOtherServices = new ArrayList<>(otherServices); } else { - Set changes = new HashSet<>(); - Map> currentMap = getServiceKeyListMap(currentOtherServices); - Map> newMap = getServiceKeyListMap(otherServices); + Set changes = new HashSet<>(); + Map> currentMap = getServiceKeyListMap(currentOtherServices); + Map> newMap = getServiceKeyListMap(otherServices); currentOtherServices = otherServices; currentMap.forEach((key, list) -> { if (!list.equals(newMap.get(key))) { @@ -327,19 +325,17 @@ public class HashPartitionService implements PartitionService { return list == null ? 0 : list.size(); } - private Map> getServiceKeyListMap(List services) { - final Map> currentMap = new HashMap<>(); + private Map> getServiceKeyListMap(List services) { + final Map> currentMap = new HashMap<>(); services.forEach(serviceInfo -> { for (String serviceTypeStr : serviceInfo.getServiceTypesList()) { ServiceType serviceType = ServiceType.valueOf(serviceTypeStr.toUpperCase()); if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) { -// for (TransportProtos.QueueInfo queue : serviceInfo.getRuleEngineQueuesList()) { -// ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType, queue.getName()), getSystemOrIsolatedTenantId(serviceInfo)); -// currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); -// } + partitionTopicsMap.keySet().forEach(queueKey -> + currentMap.computeIfAbsent(queueKey, key -> new ArrayList<>()).add(serviceInfo)); } else { - ServiceQueueKey serviceQueueKey = new ServiceQueueKey(new ServiceQueue(serviceType)); - currentMap.computeIfAbsent(serviceQueueKey, key -> new ArrayList<>()).add(serviceInfo); + QueueKey queueKey = new QueueKey(serviceType); + currentMap.computeIfAbsent(queueKey, key -> new ArrayList<>()).add(serviceInfo); } } }); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ClusterTopologyChangeEvent.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ClusterTopologyChangeEvent.java index 8aadf8515d..fd0911423a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ClusterTopologyChangeEvent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ClusterTopologyChangeEvent.java @@ -16,20 +16,19 @@ package org.thingsboard.server.queue.discovery.event; import lombok.Getter; -import org.thingsboard.server.common.msg.queue.ServiceQueueKey; +import org.thingsboard.server.queue.discovery.QueueKey; import java.util.Set; - public class ClusterTopologyChangeEvent extends TbApplicationEvent { private static final long serialVersionUID = -2441739930040282254L; @Getter - private final Set serviceQueueKeys; + private final Set queueKeys; - public ClusterTopologyChangeEvent(Object source, Set serviceQueueKeys) { + public ClusterTopologyChangeEvent(Object source, Set queueKeys) { super(source); - this.serviceQueueKeys = serviceQueueKeys; + this.queueKeys = queueKeys; } } diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 39cb9b35d0..51a4bf4492 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -269,8 +269,6 @@ service: type: "${TB_SERVICE_TYPE:tb-transport}" # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" - tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. - metrics: # Enable/disable actuator metrics. diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 29d8a1d381..7574687ecc 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -257,8 +257,6 @@ service: type: "${TB_SERVICE_TYPE:tb-transport}" # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" - tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. - metrics: # Enable/disable actuator metrics. diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 361ac7c651..19d70e0bc2 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -336,8 +336,6 @@ service: type: "${TB_SERVICE_TYPE:tb-transport}" # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" - tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. - metrics: # Enable/disable actuator metrics. diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 1b84701ccf..1a6f04e598 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -287,7 +287,6 @@ service: type: "${TB_SERVICE_TYPE:tb-transport}" # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" - tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. metrics: # Enable/disable actuator metrics. diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 7562af359b..6ff1a37442 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -237,7 +237,6 @@ service: type: "${TB_SERVICE_TYPE:tb-transport}" # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" - tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. metrics: # Enable/disable actuator metrics. From 7071c7a6bc9deb72bf579e4db868c7d98146c529 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 20 May 2022 17:33:24 +0300 Subject: [PATCH 56/58] Implementation of the Git Queue service client --- .../server/controller/BaseController.java | 21 + .../EntitiesVersionControlController.java | 85 ++-- .../install/SqlDatabaseUpgradeService.java | 12 - .../queue/DefaultTbClusterService.java | 8 + .../service/sync/vc/CommitGitRequest.java | 33 ++ .../DefaultEntitiesVersionControlService.java | 215 +++++---- .../DefaultGitVersionControlQueueService.java | 287 +++++++++++ .../sync/vc/EntitiesContentGitRequest.java | 37 ++ .../vc/EntitiesVersionControlService.java | 19 +- .../sync/vc/EntityContentGitRequest.java | 34 ++ .../vc/GitVersionControlQueueService.java | 57 +++ .../sync/vc/ListBranchesGitRequest.java | 29 ++ .../sync/vc/ListEntitiesGitRequest.java | 30 ++ .../sync/vc/ListVersionsGitRequest.java | 31 ++ .../vc/LocalGitVersionControlService.java | 452 +++++++++--------- .../service/sync/vc/PendingGitRequest.java | 37 ++ .../src/main/resources/thingsboard.yml | 5 +- .../server/cluster/TbClusterService.java | 7 +- common/cluster-api/src/main/proto/queue.proto | 96 +++- .../server/common/msg/queue/ServiceType.java | 2 +- .../queue/discovery/HashPartitionService.java | 10 +- .../queue/kafka/TbKafkaTopicConfigs.java | 6 + .../provider/AwsSqsMonolithQueueFactory.java | 7 + .../provider/AwsSqsTbCoreQueueFactory.java | 7 + .../InMemoryMonolithQueueFactory.java | 6 + .../provider/KafkaMonolithQueueFactory.java | 36 +- .../provider/KafkaTbCoreQueueFactory.java | 20 + .../KafkaTbVersionControlQueueFactory.java | 116 +++++ .../provider/PubSubMonolithQueueFactory.java | 7 + .../provider/PubSubTbCoreQueueFactory.java | 7 + .../RabbitMqMonolithQueueFactory.java | 7 + .../provider/RabbitMqTbCoreQueueFactory.java | 7 + .../ServiceBusMonolithQueueFactory.java | 7 + .../ServiceBusTbCoreQueueFactory.java | 7 + .../queue/provider/TbCoreQueueFactory.java | 8 + .../provider/TbCoreQueueProducerProvider.java | 8 + .../provider/TbQueueProducerProvider.java | 8 + .../TbRuleEngineProducerProvider.java | 6 + .../TbTransportQueueProducerProvider.java | 6 + .../TbVersionControlProducerProvider.java | 84 ++++ .../TbVersionControlQueueFactory.java | 44 ++ .../TbQueueVersionControlSettings.java | 34 ++ .../queue/util/TbVersionControlComponent.java | 26 + common/version-control/pom.xml | 24 - .../sync/vc/GitVersionControlService.java | 11 - .../version-control/src/main/proto/vc.proto | 71 --- 46 files changed, 1579 insertions(+), 498 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/CommitGitRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesContentGitRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/EntityContentGitRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/ListBranchesGitRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/ListEntitiesGitRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/ListVersionsGitRequest.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlQueueFactory.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueVersionControlSettings.java create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/util/TbVersionControlComponent.java delete mode 100644 common/version-control/src/main/proto/vc.proto diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 195ea9a3ee..709b809823 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -18,6 +18,10 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -27,6 +31,7 @@ import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.async.DeferredResult; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; @@ -948,4 +953,20 @@ public abstract class BaseController { return MediaType.APPLICATION_OCTET_STREAM; } } + + protected DeferredResult wrapFuture(ListenableFuture future) { + final DeferredResult deferredResult = new DeferredResult<>(); + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(T result) { + deferredResult.setResult(result); + } + + @Override + public void onFailure(Throwable t) { + deferredResult.setErrorResult(t); + } + }, MoreExecutors.directExecutor()); + return deferredResult; + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java b/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java index bba5d20b06..4c5c7dad65 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java @@ -15,16 +15,26 @@ */ package org.thingsboard.server.controller; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import io.swagger.annotations.ApiOperation; import lombok.Data; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.device.claim.ClaimResponse; +import org.thingsboard.server.dao.device.claim.ClaimResult; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.common.data.sync.vc.EntityVersion; @@ -34,6 +44,7 @@ import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -90,16 +101,15 @@ public class EntitiesVersionControlController extends BaseController { " }\n" + "}\n```") @PostMapping("/version") - public VersionCreationResult saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws ThingsboardException { + public DeferredResult saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws ThingsboardException { SecurityUser user = getCurrentUser(); try { - return versionControlService.saveEntitiesVersion(user, request); + return wrapFuture(versionControlService.saveEntitiesVersion(user, request)); } catch (Exception e) { throw handleException(e); } } - @ApiOperation(value = "", notes = "" + "```\n[\n" + " {\n" + @@ -108,12 +118,12 @@ public class EntitiesVersionControlController extends BaseController { " }\n" + "]\n```") @GetMapping("/version/{branch}/{entityType}/{externalEntityUuid}") - public List listEntityVersions(@PathVariable String branch, - @PathVariable EntityType entityType, - @PathVariable UUID externalEntityUuid) throws ThingsboardException { + public DeferredResult> listEntityVersions(@PathVariable String branch, + @PathVariable EntityType entityType, + @PathVariable UUID externalEntityUuid) throws ThingsboardException { try { EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid); - return versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId); + return wrapFuture(versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId)); } catch (Exception e) { throw handleException(e); } @@ -127,10 +137,10 @@ public class EntitiesVersionControlController extends BaseController { " }\n" + "]\n```") @GetMapping("/version/{branch}/{entityType}") - public List listEntityTypeVersions(@PathVariable String branch, - @PathVariable EntityType entityType) throws ThingsboardException { + public DeferredResult> listEntityTypeVersions(@PathVariable String branch, + @PathVariable EntityType entityType) throws ThingsboardException { try { - return versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType); + return wrapFuture(versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType)); } catch (Exception e) { throw handleException(e); } @@ -152,9 +162,9 @@ public class EntitiesVersionControlController extends BaseController { " }\n" + "]\n```") @GetMapping("/version/{branch}") - public List listVersions(@PathVariable String branch) throws ThingsboardException { + public DeferredResult> listVersions(@PathVariable String branch) throws ThingsboardException { try { - return versionControlService.listVersions(getTenantId(), branch); + return wrapFuture(versionControlService.listVersions(getTenantId(), branch)); } catch (Exception e) { throw handleException(e); } @@ -162,21 +172,21 @@ public class EntitiesVersionControlController extends BaseController { @GetMapping("/entity/{branch}/{entityType}/{versionId}") - public List listEntitiesAtVersion(@PathVariable String branch, - @PathVariable EntityType entityType, - @PathVariable String versionId) throws ThingsboardException { + public DeferredResult> listEntitiesAtVersion(@PathVariable String branch, + @PathVariable EntityType entityType, + @PathVariable String versionId) throws ThingsboardException { try { - return versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType); + return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType)); } catch (Exception e) { throw handleException(e); } } @GetMapping("/entity/{branch}/{versionId}") - public List listAllEntitiesAtVersion(@PathVariable String branch, - @PathVariable String versionId) throws ThingsboardException { + public DeferredResult> listAllEntitiesAtVersion(@PathVariable String branch, + @PathVariable String versionId) throws ThingsboardException { try { - return versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId); + return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId)); } catch (Exception e) { throw handleException(e); } @@ -216,20 +226,10 @@ public class EntitiesVersionControlController extends BaseController { " }\n" + "}\n```") @PostMapping("/entity") - public List loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws ThingsboardException { + public DeferredResult> loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws ThingsboardException { SecurityUser user = getCurrentUser(); try { - String versionId = request.getVersionId(); - if (versionId == null) { - List versions = versionControlService.listVersions(user.getTenantId(), request.getBranch()); - if (versions.size() > 0) { - versionId = versions.get(0).getId(); - } else { - throw new IllegalArgumentException("No versions available in branch"); - } - } - - return versionControlService.loadEntitiesVersion(user, request); + return wrapFuture(versionControlService.loadEntitiesVersion(user, request)); } catch (Exception e) { throw handleException(e); } @@ -252,19 +252,22 @@ public class EntitiesVersionControlController extends BaseController { " }\n" + "]\n\n```") @GetMapping("/branches") - public List listBranches() throws ThingsboardException { + public DeferredResult> listBranches() throws ThingsboardException { try { - List remoteBranches = versionControlService.listBranches(getTenantId()); - List infos = new ArrayList<>(); + final TenantId tenantId = getTenantId(); + ListenableFuture> branches = versionControlService.listBranches(tenantId); + return wrapFuture(Futures.transform(branches, remoteBranches -> { + List infos = new ArrayList<>(); - String defaultBranch = versionControlService.getVersionControlSettings(getTenantId()).getDefaultBranch(); - if (StringUtils.isNotEmpty(defaultBranch)) { - remoteBranches.remove(defaultBranch); - infos.add(new BranchInfo(defaultBranch, true)); - } + String defaultBranch = versionControlService.getVersionControlSettings(tenantId).getDefaultBranch(); + if (StringUtils.isNotEmpty(defaultBranch)) { + remoteBranches.remove(defaultBranch); + infos.add(new BranchInfo(defaultBranch, true)); + } - remoteBranches.forEach(branch -> infos.add(new BranchInfo(branch, false))); - return infos; + remoteBranches.forEach(branch -> infos.add(new BranchInfo(branch, false))); + return infos; + }, MoreExecutors.directExecutor())); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index b1bdbf61b8..db2352b706 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -647,18 +647,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; - case "3.3.4": - try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { - log.info("Updating schema ..."); - schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", SCHEMA_UPDATE_SQL); - loadSql(schemaUpdateFile, conn); - log.info("Updating schema settings..."); - conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;"); - log.info("Schema updated."); - } catch (Exception e) { - log.error("Failed updating schema!!!", e); - } - break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 2806c35cda..4a52ea2287 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -135,6 +135,14 @@ public class DefaultTbClusterService implements TbClusterService { toCoreMsgs.incrementAndGet(); } + @Override + public void pushMsgToVersionControl(TenantId tenantId, TransportProtos.ToVersionControlServiceMsg msg, TbQueueCallback callback) { + TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_VC_EXECUTOR, tenantId, tenantId); + log.trace("PUSHING msg: {} to:{}", msg, tpi); + producerProvider.getTbVersionControlMsgProducer().send(tpi, new TbProtoQueueMsg<>(tenantId.getId(), msg), callback); + toCoreMsgs.incrementAndGet(); + } + @Override public void pushNotificationToCore(String serviceId, FromDeviceRpcResponse response, TbQueueCallback callback) { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/CommitGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/CommitGitRequest.java new file mode 100644 index 0000000000..b510ffa62c --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/CommitGitRequest.java @@ -0,0 +1,33 @@ +/** + * 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.sync.vc; + +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; +import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; + +import java.util.UUID; + +public class CommitGitRequest extends PendingGitRequest { + + private final VersionCreateRequest request; + + public CommitGitRequest(TenantId tenantId, VersionCreateRequest request) { + super(tenantId); + this.request = request; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java index dcc96b7d17..3fb47a8bd6 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java @@ -15,12 +15,18 @@ */ package org.thingsboard.server.service.sync.vc; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.support.TransactionTemplate; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; @@ -33,7 +39,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.sync.vc.*; import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadConfig; import org.thingsboard.server.dao.DaoUtil; -import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; @@ -56,6 +61,8 @@ import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadConfig import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest; import org.thingsboard.server.common.data.sync.ThrowingRunnable; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -72,118 +79,137 @@ import java.util.stream.Collectors; @Slf4j public class DefaultEntitiesVersionControlService implements EntitiesVersionControlService { - private final GitVersionControlService gitService; + private final GitVersionControlQueueService gitServiceQueue; private final EntitiesExportImportService exportImportService; private final ExportableEntitiesService exportableEntitiesService; private final AdminSettingsService adminSettingsService; - private final EntityService entityService; private final TransactionTemplate transactionTemplate; + private ListeningExecutorService executor; + + @Value("${vc.thread_pool_size:4}") + private int threadPoolSize; + + @PostConstruct + public void init() { + executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, DefaultEntitiesVersionControlService.class)); + } + + @PreDestroy + public void shutdown() { + if (executor != null) { + executor.shutdownNow(); + } + } + + @SuppressWarnings("UnstableApiUsage") @Override - public VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception { - var commit = gitService.prepareCommit(user.getTenantId(), request); + public ListenableFuture saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception { + var pendingCommit = gitServiceQueue.prepareCommit(user.getTenantId(), request); - switch (request.getType()) { - case SINGLE_ENTITY: { - SingleEntityVersionCreateRequest versionCreateRequest = (SingleEntityVersionCreateRequest) request; - saveEntityData(user, commit, versionCreateRequest.getEntityId(), versionCreateRequest.getConfig()); - break; - } - case COMPLEX: { - ComplexVersionCreateRequest versionCreateRequest = (ComplexVersionCreateRequest) request; - versionCreateRequest.getEntityTypes().forEach((entityType, config) -> { - if (ObjectUtils.defaultIfNull(config.getSyncStrategy(), versionCreateRequest.getSyncStrategy()) == SyncStrategy.OVERWRITE) { - gitService.deleteAll(commit, entityType); - } + return Futures.transformAsync(pendingCommit, commit -> { + List> gitFutures = new ArrayList<>(); + switch (request.getType()) { + case SINGLE_ENTITY: { + SingleEntityVersionCreateRequest versionCreateRequest = (SingleEntityVersionCreateRequest) request; + gitFutures.add(saveEntityData(user, commit, versionCreateRequest.getEntityId(), versionCreateRequest.getConfig())); + break; + } + case COMPLEX: { + ComplexVersionCreateRequest versionCreateRequest = (ComplexVersionCreateRequest) request; + versionCreateRequest.getEntityTypes().forEach((entityType, config) -> { + if (ObjectUtils.defaultIfNull(config.getSyncStrategy(), versionCreateRequest.getSyncStrategy()) == SyncStrategy.OVERWRITE) { + gitFutures.add(gitServiceQueue.deleteAll(commit, entityType)); + } - if (config.isAllEntities()) { - DaoUtil.processInBatches(pageLink -> { - return exportableEntitiesService.findEntitiesByTenantId(user.getTenantId(), entityType, pageLink); - }, 100, entity -> { - try { - saveEntityData(user, commit, entity.getId(), config); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } else { - for (UUID entityId : config.getEntityIds()) { - try { - saveEntityData(user, commit, EntityIdFactory.getByTypeAndUuid(entityType, entityId), config); - } catch (Exception e) { - throw new RuntimeException(e); + if (config.isAllEntities()) { + DaoUtil.processInBatches(pageLink -> exportableEntitiesService.findEntitiesByTenantId(user.getTenantId(), entityType, pageLink) + , 100, entity -> { + try { + gitFutures.add(saveEntityData(user, commit, entity.getId(), config)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } else { + for (UUID entityId : config.getEntityIds()) { + try { + gitFutures.add(saveEntityData(user, commit, EntityIdFactory.getByTypeAndUuid(entityType, entityId), config)); + } catch (Exception e) { + throw new RuntimeException(e); + } } } - } - - }); - break; + }); + break; + } } - } - - return gitService.push(commit); + return Futures.transformAsync(Futures.allAsList(gitFutures), success -> gitServiceQueue.push(commit), executor); + }, executor); } - private void saveEntityData(SecurityUser user, PendingCommit commit, EntityId entityId, VersionCreateConfig config) throws Exception { + private ListenableFuture saveEntityData(SecurityUser user, CommitGitRequest commit, EntityId entityId, VersionCreateConfig config) throws Exception { EntityExportData> entityData = exportImportService.exportEntity(user, entityId, EntityExportSettings.builder() .exportRelations(config.isSaveRelations()) .build()); - gitService.addToCommit(commit, entityData); + return gitServiceQueue.addToCommit(commit, entityData); } - @Override - public List listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception { - return gitService.listVersions(tenantId, branch, externalId); + public ListenableFuture> listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception { + return gitServiceQueue.listVersions(tenantId, branch, externalId); } @Override - public List listEntityTypeVersions(TenantId tenantId, String branch, EntityType entityType) throws Exception { - return gitService.listVersions(tenantId, branch, entityType); + public ListenableFuture> listEntityTypeVersions(TenantId tenantId, String branch, EntityType entityType) throws Exception { + return gitServiceQueue.listVersions(tenantId, branch, entityType); } @Override - public List listVersions(TenantId tenantId, String branch) throws Exception { - return gitService.listVersions(tenantId, branch); + public ListenableFuture> listVersions(TenantId tenantId, String branch) throws Exception { + return gitServiceQueue.listVersions(tenantId, branch); } @Override - public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception { - return gitService.listEntitiesAtVersion(tenantId, branch, versionId, entityType); + public ListenableFuture> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception { + return gitServiceQueue.listEntitiesAtVersion(tenantId, branch, versionId, entityType); } @Override - public List listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception { - return gitService.listEntitiesAtVersion(tenantId, branch, versionId); + public ListenableFuture> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception { + return gitServiceQueue.listEntitiesAtVersion(tenantId, branch, versionId); } + @SuppressWarnings({"UnstableApiUsage", "rawtypes"}) @Override - public List loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception { + public ListenableFuture> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception { switch (request.getType()) { case SINGLE_ENTITY: { SingleEntityVersionLoadRequest versionLoadRequest = (SingleEntityVersionLoadRequest) request; VersionLoadConfig config = versionLoadRequest.getConfig(); - EntityImportResult importResult = transactionTemplate.execute(status -> { - try { - EntityExportData entityData = gitService.getEntity(user.getTenantId(), request.getVersionId(), versionLoadRequest.getExternalEntityId()); - return exportImportService.importEntity(user, entityData, EntityImportSettings.builder() - .updateRelations(config.isLoadRelations()) - .findExistingByName(config.isFindExistingEntityByName()) - .build(), true, true); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - return List.of(VersionLoadResult.builder() - .entityType(importResult.getEntityType()) - .created(importResult.getOldEntity() == null ? 1 : 0) - .updated(importResult.getOldEntity() != null ? 1 : 0) - .deleted(0) - .build()); + ListenableFuture future = gitServiceQueue.getEntity(user.getTenantId(), request.getVersionId(), versionLoadRequest.getExternalEntityId()); + Futures.transform(future, entityData -> { + EntityImportResult importResult = transactionTemplate.execute(status -> { + try { + return exportImportService.importEntity(user, entityData, EntityImportSettings.builder() + .updateRelations(config.isLoadRelations()) + .findExistingByName(config.isFindExistingEntityByName()) + .build(), true, true); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return List.of(VersionLoadResult.builder() + .entityType(importResult.getEntityType()) + .created(importResult.getOldEntity() == null ? 1 : 0) + .updated(importResult.getOldEntity() != null ? 1 : 0) + .deleted(0) + .build()); + }, executor); } case ENTITY_TYPE: { EntityTypeVersionLoadRequest versionLoadRequest = (EntityTypeVersionLoadRequest) request; - return transactionTemplate.execute(status -> { + return executor.submit(() -> transactionTemplate.execute(status -> { Map results = new HashMap<>(); Map> importedEntities = new HashMap<>(); List saveReferencesCallbacks = new ArrayList<>(); @@ -199,9 +225,9 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont try { int limit = 100; int offset = 0; - List> entityDataList; + List entityDataList; do { - entityDataList = gitService.getEntities(user.getTenantId(), request.getBranch(), request.getVersionId(), entityType, offset, limit); + entityDataList = gitServiceQueue.getEntities(user.getTenantId(), request.getVersionId(), entityType, offset, limit).get(); for (EntityExportData entityData : entityDataList) { EntityImportResult importResult = exportImportService.importEntity(user, entityData, EntityImportSettings.builder() .updateRelations(config.isLoadRelations()) @@ -215,7 +241,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont } offset += limit; importedEntities.computeIfAbsent(entityType, t -> new HashSet<>()) - .addAll(entityDataList.stream().map(entityData -> entityData.getEntity().getId()).collect(Collectors.toSet())); + .addAll(entityDataList.stream().map(entityData -> entityData.getEntity().getExternalId()).collect(Collectors.toSet())); } while (entityDataList.size() == limit); } catch (Exception e) { throw new RuntimeException(e); @@ -263,7 +289,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont } } return new ArrayList<>(results.values()); - }); + })); } default: throw new IllegalArgumentException("Unsupported version load request"); @@ -272,8 +298,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont @Override - public List listBranches(TenantId tenantId) throws Exception { - return gitService.listBranches(tenantId); + public ListenableFuture> listBranches(TenantId tenantId) throws Exception { + return gitServiceQueue.listBranches(tenantId); } @Override @@ -304,32 +330,35 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont } catch (Exception e) { throw new RuntimeException("Failed to load version control settings!", e); } - try { - gitService.clearRepository(tenantId); - gitService.initRepository(tenantId, savedVersionControlSettings); - } catch (Exception e) { - throw new RuntimeException("Failed to init repository!", e); - } + //TODO: ashvayka +// try { +// gitService.clearRepository(tenantId); +// gitService.initRepository(tenantId, savedVersionControlSettings); +// } catch (Exception e) { +// throw new RuntimeException("Failed to init repository!", e); +// } return savedVersionControlSettings; } @Override public void deleteVersionControlSettings(TenantId tenantId) { - if (adminSettingsService.deleteAdminSettings(tenantId, SETTINGS_KEY)) { - gitService.clearRepository(tenantId); - } + //TODO: ashvayka +// if (adminSettingsService.deleteAdminSettings(tenantId, SETTINGS_KEY)) { +// gitService.clearRepository(tenantId); +// } } @Override public void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws ThingsboardException { EntitiesVersionControlSettings storedSettings = getVersionControlSettings(tenantId); settings = this.restoreCredentials(settings, storedSettings); - try { - gitService.testRepository(tenantId, settings); - } catch (Exception e) { - throw new ThingsboardException(String.format("Unable to access repository: %s", e.getMessage()), - ThingsboardErrorCode.GENERAL); - } + //TODO: ashvayka +// try { +// gitService.testRepository(tenantId, settings); +// } catch (Exception e) { +// throw new ThingsboardException(String.format("Unable to access repository: %s", e.getMessage()), +// ThingsboardErrorCode.GENERAL); +// } } private EntitiesVersionControlSettings restoreCredentials(EntitiesVersionControlSettings settings, EntitiesVersionControlSettings storedSettings) { diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java new file mode 100644 index 0000000000..410847fb6b --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java @@ -0,0 +1,287 @@ +/** + * 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.sync.vc; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; +import org.thingsboard.server.common.data.sync.vc.EntityVersion; +import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; +import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; +import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.CommitRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ListEntitiesRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ListVersionsRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.EntityContentRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.EntitiesContentRequestMsg; +import org.thingsboard.server.gen.transport.TransportProtos.PrepareMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; +import org.thingsboard.server.queue.TbQueueCallback; +import org.thingsboard.server.queue.TbQueueMsgMetadata; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import org.thingsboard.server.queue.util.TbCoreComponent; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; + +@TbCoreComponent +@Service +@RequiredArgsConstructor +public class DefaultGitVersionControlQueueService implements GitVersionControlQueueService { + + private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT); + private final TbServiceInfoProvider serviceInfoProvider; + private final TbClusterService clusterService; + private final Map> pendingRequestMap = new HashMap<>(); + + @Override + public ListenableFuture prepareCommit(TenantId tenantId, VersionCreateRequest request) { + SettableFuture future = SettableFuture.create(); + + CommitGitRequest commit = new CommitGitRequest(tenantId, request); + registerAndSend(commit, builder -> builder.setCommitRequest( + CommitRequestMsg.newBuilder().setPrepareMsg(getCommitPrepareMsg(request)).build() + ).build(), wrap(future, commit)); + + return future; + } + + @Override + public ListenableFuture addToCommit(CommitGitRequest commit, EntityExportData> entityData) { + SettableFuture future = SettableFuture.create(); + + String path = getRelativePath(entityData.getEntityType(), entityData.getEntity().getId()); + String entityDataJson; + try { + entityDataJson = jsonWriter.writeValueAsString(entityData); + } catch (IOException e) { + //TODO: analyze and return meaningful exceptions that we can show to the client; + throw new RuntimeException(e); + } + + registerAndSend(commit, builder -> builder.setCommitRequest( + CommitRequestMsg.newBuilder().setAddMsg( + TransportProtos.AddMsg.newBuilder() + .setRelativePath(path).setEntityDataJson(entityDataJson).build() + ).build() + ).build(), wrap(commit.getFuture(), null)); + return future; + } + + @Override + public ListenableFuture deleteAll(CommitGitRequest commit, EntityType entityType) { + SettableFuture future = SettableFuture.create(); + + String path = getRelativePath(entityType, null); + + registerAndSend(commit, builder -> builder.setCommitRequest( + CommitRequestMsg.newBuilder().setDeleteMsg( + TransportProtos.DeleteMsg.newBuilder().setRelativePath(path).build() + ).build() + ).build(), wrap(commit.getFuture(), null)); + + return future; + } + + @Override + public ListenableFuture push(CommitGitRequest commit) { + registerAndSend(commit, builder -> builder.setCommitRequest( + CommitRequestMsg.newBuilder().setPushMsg( + TransportProtos.PushMsg.newBuilder().build() + ).build() + ).build(), wrap(commit.getFuture())); + + return commit.getFuture(); + } + + @Override + public ListenableFuture> listVersions(TenantId tenantId, String branch) { + return listVersions(tenantId, ListVersionsRequestMsg.newBuilder() + .setBranchName(branch).build()); + } + + @Override + public ListenableFuture> listVersions(TenantId tenantId, String branch, EntityType entityType) { + return listVersions(tenantId, ListVersionsRequestMsg.newBuilder() + .setBranchName(branch).setEntityType(entityType.name()) + .build()); + } + + @Override + public ListenableFuture> listVersions(TenantId tenantId, String branch, EntityId entityId) { + return listVersions(tenantId, ListVersionsRequestMsg.newBuilder() + .setBranchName(branch) + .setEntityType(entityId.getEntityType().name()) + .setEntityIdMSB(entityId.getId().getMostSignificantBits()) + .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) + .build()); + } + + private ListenableFuture> listVersions(TenantId tenantId, ListVersionsRequestMsg requestMsg) { + ListVersionsGitRequest request = new ListVersionsGitRequest(tenantId); + + registerAndSend(request, builder -> builder.setListVersionRequest(requestMsg).build(), wrap(request.getFuture())); + + return request.getFuture(); + } + + @Override + public ListenableFuture> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) { + return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder() + .setBranchName(branch) + .setVersionId(versionId) + .setEntityType(entityType.name()) + .build()); + } + + @Override + public ListenableFuture> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) { + return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder() + .setBranchName(branch) + .setVersionId(versionId) + .build()); + } + + private ListenableFuture> listEntitiesAtVersion(TenantId tenantId, TransportProtos.ListEntitiesRequestMsg requestMsg) { + ListEntitiesGitRequest request = new ListEntitiesGitRequest(tenantId); + + registerAndSend(request, builder -> builder.setListEntitiesRequest(requestMsg).build(), wrap(request.getFuture())); + + return request.getFuture(); + } + + @Override + public ListenableFuture> listBranches(TenantId tenantId) { + ListBranchesGitRequest request = new ListBranchesGitRequest(tenantId); + + registerAndSend(request, builder -> builder.setListBranchesRequest(TransportProtos.ListBranchesRequestMsg.newBuilder().build()).build(), wrap(request.getFuture())); + + return request.getFuture(); + } + + private void registerAndSend(PendingGitRequest request, Function enrichFunction, TbQueueCallback callback) { + if (!request.getFuture().isDone()) { + pendingRequestMap.putIfAbsent(request.getRequestId(), request); + clusterService.pushMsgToVersionControl(request.getTenantId(), enrichFunction.apply(newRequestProto(request)), callback); + } else { + throw new RuntimeException("Future is already done!"); + } + } + + @Override + public ListenableFuture getEntity(TenantId tenantId, String versionId, EntityId entityId) { + EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId); + registerAndSend(request, builder -> builder.setEntityContentRequest(EntityContentRequestMsg.newBuilder() + .setVersionId(versionId) + .setEntityType(entityId.getEntityType().name()) + .setEntityIdMSB(entityId.getId().getMostSignificantBits()) + .setEntityIdLSB(entityId.getId().getLeastSignificantBits())).build() + , wrap(request.getFuture())); + + return request.getFuture(); +// try { +// String entityDataJson = gitRepositoryService.getFileContentAtCommit(tenantId, +// getRelativePath(entityId.getEntityType(), entityId.getId().toString()), versionId); +// return JacksonUtil.fromString(entityDataJson, EntityExportData.class); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } + } + + @Override + public ListenableFuture> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) { + EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType); + + registerAndSend(request, builder -> builder.setEntitiesContentRequest(EntitiesContentRequestMsg.newBuilder() + .setVersionId(versionId) + .setEntityType(entityType.name()) + .setOffset(offset) + .setLimit(limit) + ).build() + , wrap(request.getFuture())); + + return request.getFuture(); + } + + private static TbQueueCallback wrap(SettableFuture future) { + return new TbQueueCallback() { + @Override + public void onSuccess(TbQueueMsgMetadata metadata) { + } + + @Override + public void onFailure(Throwable t) { + future.setException(t); + } + }; + } + + private static TbQueueCallback wrap(SettableFuture future, T value) { + return new TbQueueCallback() { + @Override + public void onSuccess(TbQueueMsgMetadata metadata) { + future.set(value); + } + + @Override + public void onFailure(Throwable t) { + future.setException(t); + } + }; + } + + private static String getRelativePath(EntityType entityType, EntityId entityId) { + String path = entityType.name().toLowerCase(); + if (entityId != null) { + path += "/" + entityId + ".json"; + } + return path; + } + + private static PrepareMsg getCommitPrepareMsg(VersionCreateRequest request) { + return PrepareMsg.newBuilder().setCommitMsg(request.getVersionName()).setBranchName(request.getBranch()).build(); + } + + private ToVersionControlServiceMsg.Builder newRequestProto(PendingGitRequest request) { + var tenantId = request.getTenantId(); + var requestId = request.getRequestId(); + return ToVersionControlServiceMsg.newBuilder() + .setNodeId(serviceInfoProvider.getServiceId()) + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) + .setRequestIdMSB(requestId.getMostSignificantBits()) + .setRequestIdLSB(requestId.getLeastSignificantBits()); + + } +} + diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesContentGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesContentGitRequest.java new file mode 100644 index 0000000000..2ded932e44 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesContentGitRequest.java @@ -0,0 +1,37 @@ +/** + * 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.sync.vc; + +import lombok.Getter; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; + +import java.util.List; + +@Getter +public class EntitiesContentGitRequest extends PendingGitRequest> { + + private final String versionId; + private final EntityType entityType; + + public EntitiesContentGitRequest(TenantId tenantId, String versionId, EntityType entityType) { + super(tenantId); + this.versionId = versionId; + this.entityType = entityType; + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java index 28f095123c..02afafedad 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.sync.vc; +import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; @@ -34,25 +35,23 @@ public interface EntitiesVersionControlService { String SETTINGS_KEY = "entitiesVersionControl"; - VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception; + ListenableFuture saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception; + ListenableFuture> listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception; - List listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception; + ListenableFuture> listEntityTypeVersions(TenantId tenantId, String branch, EntityType entityType) throws Exception; - List listEntityTypeVersions(TenantId tenantId, String branch, EntityType entityType) throws Exception; + ListenableFuture> listVersions(TenantId tenantId, String branch) throws Exception; - List listVersions(TenantId tenantId, String branch) throws Exception; + ListenableFuture> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception; + ListenableFuture> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception; - List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception; - List listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception; + ListenableFuture> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception; - List loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception; - - - List listBranches(TenantId tenantId) throws Exception; + ListenableFuture> listBranches(TenantId tenantId) throws Exception; EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntityContentGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntityContentGitRequest.java new file mode 100644 index 0000000000..c9ce3c76af --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntityContentGitRequest.java @@ -0,0 +1,34 @@ +/** + * 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.sync.vc; + +import lombok.Getter; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; + +@Getter +public class EntityContentGitRequest extends PendingGitRequest { + + private final String versionId; + private final EntityId entityId; + + public EntityContentGitRequest(TenantId tenantId, String versionId, EntityId entityId) { + super(tenantId); + this.versionId = versionId; + this.entityId = entityId; + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java new file mode 100644 index 0000000000..e7b7171ea0 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java @@ -0,0 +1,57 @@ +/** + * 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.sync.vc; + +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; +import org.thingsboard.server.common.data.sync.vc.EntityVersion; +import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; +import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; +import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; + +import java.util.List; + +public interface GitVersionControlQueueService { + + ListenableFuture prepareCommit(TenantId tenantId, VersionCreateRequest request); + + ListenableFuture addToCommit(CommitGitRequest commit, EntityExportData> entityData); + + ListenableFuture deleteAll(CommitGitRequest pendingCommit, EntityType entityType); + + ListenableFuture push(CommitGitRequest commit); + + ListenableFuture> listVersions(TenantId tenantId, String branch); + + ListenableFuture> listVersions(TenantId tenantId, String branch, EntityType entityType); + + ListenableFuture> listVersions(TenantId tenantId, String branch, EntityId entityId); + + ListenableFuture> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType); + + ListenableFuture> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId); + + ListenableFuture> listBranches(TenantId tenantId); + + ListenableFuture getEntity(TenantId tenantId, String versionId, EntityId entityId); + + ListenableFuture> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit); + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/ListBranchesGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/ListBranchesGitRequest.java new file mode 100644 index 0000000000..c8219641da --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/ListBranchesGitRequest.java @@ -0,0 +1,29 @@ +/** + * 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.sync.vc; + +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; + +import java.util.List; + +public class ListBranchesGitRequest extends PendingGitRequest> { + + public ListBranchesGitRequest(TenantId tenantId) { + super(tenantId); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/ListEntitiesGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/ListEntitiesGitRequest.java new file mode 100644 index 0000000000..0c7216ef49 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/ListEntitiesGitRequest.java @@ -0,0 +1,30 @@ +/** + * 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.sync.vc; + +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.vc.EntityVersion; +import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; + +import java.util.List; + +public class ListEntitiesGitRequest extends PendingGitRequest> { + + public ListEntitiesGitRequest(TenantId tenantId) { + super(tenantId); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/ListVersionsGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/ListVersionsGitRequest.java new file mode 100644 index 0000000000..0c8e51042b --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/ListVersionsGitRequest.java @@ -0,0 +1,31 @@ +/** + * 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.sync.vc; + +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.vc.EntityVersion; +import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; +import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; + +import java.util.List; + +public class ListVersionsGitRequest extends PendingGitRequest> { + + public ListVersionsGitRequest(TenantId tenantId) { + super(tenantId); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java index d73157d256..66803e062d 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java @@ -19,18 +19,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.EntityVersion; @@ -38,7 +35,6 @@ import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; import org.thingsboard.server.dao.DaoUtil; -import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.queue.util.AfterStartUp; @@ -60,235 +56,235 @@ import java.util.stream.Collectors; @RequiredArgsConstructor @Service @ConditionalOnProperty(prefix = "vc", value = "git.service", havingValue = "local", matchIfMissing = true) -public class LocalGitVersionControlService implements GitVersionControlService { +public class LocalGitVersionControlService { private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT); private final GitRepositoryService gitRepositoryService; private final TenantDao tenantDao; private final AdminSettingsService adminSettingsService; private final ConcurrentMap tenantRepoLocks = new ConcurrentHashMap<>(); - private final Map pendingCommitMap = new HashMap<>(); - - @AfterStartUp - public void init() { - DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> { - EntitiesVersionControlSettings settings = getVersionControlSettings(tenantId); - if (settings != null) { - try { - gitRepositoryService.initRepository(tenantId, settings); - } catch (Exception e) { - log.warn("Failed to init repository for tenant {}", tenantId, e); - } - } - }); - } - - @Override - public void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { - var lock = getRepoLock(tenantId); - lock.lock(); - try { - gitRepositoryService.testRepository(tenantId, settings); - } catch (Exception e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } finally { - lock.unlock(); - } - } - - @Override - public void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { - var lock = getRepoLock(tenantId); - lock.lock(); - try { - gitRepositoryService.initRepository(tenantId, settings); - } catch (Exception e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } finally { - lock.unlock(); - } - } - - @Override - public void clearRepository(TenantId tenantId) { - var lock = getRepoLock(tenantId); - lock.lock(); - try { - gitRepositoryService.clearRepository(tenantId); - } catch (Exception e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } finally { - lock.unlock(); - } - } - - @Override - public PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request) { - var lock = getRepoLock(tenantId); - lock.lock(); - try { - var pendingCommit = new PendingCommit(tenantId, request); - PendingCommit old = pendingCommitMap.put(tenantId, pendingCommit); - if (old != null) { - gitRepositoryService.abort(old); - } - gitRepositoryService.prepareCommit(pendingCommit); - return pendingCommit; - } finally { - lock.unlock(); - } - } - - @Override - public void deleteAll(PendingCommit commit, EntityType entityType) { - doInsideLock(commit, c -> { - try { - gitRepositoryService.deleteFolderContent(commit, getRelativePath(entityType, null)); - } catch (IOException e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } - }); - } - - @Override - public void addToCommit(PendingCommit commit, EntityExportData> entityData) { - doInsideLock(commit, c -> { - String entityDataJson; - try { - entityDataJson = jsonWriter.writeValueAsString(entityData); - gitRepositoryService.add(c, getRelativePath(entityData.getEntityType(), - entityData.getEntity().getId().toString()), entityDataJson); - } catch (IOException e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } - }); - } - - @Override - public VersionCreationResult push(PendingCommit commit) { - return executeInsideLock(commit, gitRepositoryService::push); - } - - @Override - public List listVersions(TenantId tenantId, String branch) { - return listVersions(tenantId, branch, (String) null); - } - - @Override - public List listVersions(TenantId tenantId, String branch, EntityType entityType) { - return listVersions(tenantId, branch, getRelativePath(entityType, null)); - } - - @Override - public List listVersions(TenantId tenantId, String branch, EntityId entityId) { - return listVersions(tenantId, branch, getRelativePath(entityId.getEntityType(), entityId.getId().toString())); - } - - @Override - public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) { - try { - return gitRepositoryService.listEntitiesAtVersion(tenantId, branch, versionId, entityType != null ? getRelativePath(entityType, null) : null); - } catch (Exception e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } - } - - @Override - public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) { - return listEntitiesAtVersion(tenantId, branch, versionId, null); - } - - @Override - public List listBranches(TenantId tenantId) { - return gitRepositoryService.listBranches(tenantId); - } - - @Override - public List> getEntities(TenantId tenantId, String branch, String versionId, EntityType entityType, int offset, int limit) { - return listEntitiesAtVersion(tenantId, branch, versionId, entityType).stream() - .skip(offset).limit(limit) - .map(entityInfo -> getEntity(tenantId, versionId, entityInfo.getExternalId())) - .collect(Collectors.toList()); - } - - @Override - public EntityExportData getEntity(TenantId tenantId, String versionId, EntityId entityId) { - try { - String entityDataJson = gitRepositoryService.getFileContentAtCommit(tenantId, - getRelativePath(entityId.getEntityType(), entityId.getId().toString()), versionId); - return JacksonUtil.fromString(entityDataJson, EntityExportData.class); - } catch (Exception e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } - } - - private EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId) { - AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, EntitiesVersionControlService.SETTINGS_KEY); - if (adminSettings != null) { - try { - return JacksonUtil.convertValue(adminSettings.getJsonValue(), EntitiesVersionControlSettings.class); - } catch (Exception e) { - throw new RuntimeException("Failed to load version control settings!", e); - } - } - return null; - } - - private List listVersions(TenantId tenantId, String branch, String path) { - try { - return gitRepositoryService.listVersions(tenantId, branch, path); - } catch (Exception e) { - //TODO: analyze and return meaningful exceptions that we can show to the client; - throw new RuntimeException(e); - } - } - - private void doInsideLock(PendingCommit commit, Consumer r) { - var lock = getRepoLock(commit.getTenantId()); - lock.lock(); - try { - checkCommit(commit); - r.accept(commit); - } finally { - lock.unlock(); - } - } - - private T executeInsideLock(PendingCommit commit, Function c) { - var lock = getRepoLock(commit.getTenantId()); - lock.lock(); - try { - checkCommit(commit); - return c.apply(commit); - } finally { - lock.unlock(); - } - } - - private void checkCommit(PendingCommit commit) { - PendingCommit existing = pendingCommitMap.get(commit.getTenantId()); - if (existing == null || !existing.getTxId().equals(commit.getTxId())) { - throw new ConcurrentModificationException(); - } - } - - private String getRelativePath(EntityType entityType, String entityId) { - String path = entityType.name().toLowerCase(); - if (entityId != null) { - path += "/" + entityId + ".json"; - } - return path; - } - - private Lock getRepoLock(TenantId tenantId) { - return tenantRepoLocks.computeIfAbsent(tenantId, t -> new ReentrantLock()); - } +// private final Map pendingCommitMap = new HashMap<>(); +// +// @AfterStartUp +// public void init() { +// DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> { +// EntitiesVersionControlSettings settings = getVersionControlSettings(tenantId); +// if (settings != null) { +// try { +// gitRepositoryService.initRepository(tenantId, settings); +// } catch (Exception e) { +// log.warn("Failed to init repository for tenant {}", tenantId, e); +// } +// } +// }); +// } +// +// @Override +// public void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { +// var lock = getRepoLock(tenantId); +// lock.lock(); +// try { +// gitRepositoryService.testRepository(tenantId, settings); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } finally { +// lock.unlock(); +// } +// } +// +// @Override +// public void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { +// var lock = getRepoLock(tenantId); +// lock.lock(); +// try { +// gitRepositoryService.initRepository(tenantId, settings); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } finally { +// lock.unlock(); +// } +// } +// +// @Override +// public void clearRepository(TenantId tenantId) { +// var lock = getRepoLock(tenantId); +// lock.lock(); +// try { +// gitRepositoryService.clearRepository(tenantId); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } finally { +// lock.unlock(); +// } +// } +// +// @Override +// public PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request) { +// var lock = getRepoLock(tenantId); +// lock.lock(); +// try { +// var pendingCommit = new PendingCommit(tenantId, request); +// PendingCommit old = pendingCommitMap.put(tenantId, pendingCommit); +// if (old != null) { +// gitRepositoryService.abort(old); +// } +// gitRepositoryService.prepareCommit(pendingCommit); +// return pendingCommit; +// } finally { +// lock.unlock(); +// } +// } +// +// @Override +// public void deleteAll(PendingCommit commit, EntityType entityType) { +// doInsideLock(commit, c -> { +// try { +// gitRepositoryService.deleteFolderContent(commit, getRelativePath(entityType, null)); +// } catch (IOException e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } +// }); +// } +// +// @Override +// public void addToCommit(PendingCommit commit, EntityExportData> entityData) { +// doInsideLock(commit, c -> { +// String entityDataJson; +// try { +// entityDataJson = jsonWriter.writeValueAsString(entityData); +// gitRepositoryService.add(c, getRelativePath(entityData.getEntityType(), +// entityData.getEntity().getId().toString()), entityDataJson); +// } catch (IOException e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } +// }); +// } +// +// @Override +// public VersionCreationResult push(PendingCommit commit) { +// return executeInsideLock(commit, gitRepositoryService::push); +// } +// +// @Override +// public List listVersions(TenantId tenantId, String branch) { +// return listVersions(tenantId, branch, (String) null); +// } +// +// @Override +// public List listVersions(TenantId tenantId, String branch, EntityType entityType) { +// return listVersions(tenantId, branch, getRelativePath(entityType, null)); +// } +// +// @Override +// public List listVersions(TenantId tenantId, String branch, EntityId entityId) { +// return listVersions(tenantId, branch, getRelativePath(entityId.getEntityType(), entityId.getId().toString())); +// } +// +// @Override +// public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) { +// try { +// return gitRepositoryService.listEntitiesAtVersion(tenantId, branch, versionId, entityType != null ? getRelativePath(entityType, null) : null); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } +// } +// +// @Override +// public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) { +// return listEntitiesAtVersion(tenantId, branch, versionId, null); +// } +// +// @Override +// public List listBranches(TenantId tenantId) { +// return gitRepositoryService.listBranches(tenantId); +// } +// +// @Override +// public List> getEntities(TenantId tenantId, String branch, String versionId, EntityType entityType, int offset, int limit) { +// return listEntitiesAtVersion(tenantId, branch, versionId, entityType).stream() +// .skip(offset).limit(limit) +// .map(entityInfo -> getEntity(tenantId, versionId, entityInfo.getExternalId())) +// .collect(Collectors.toList()); +// } +// +// @Override +// public EntityExportData getEntity(TenantId tenantId, String versionId, EntityId entityId) { +// try { +// String entityDataJson = gitRepositoryService.getFileContentAtCommit(tenantId, +// getRelativePath(entityId.getEntityType(), entityId.getId().toString()), versionId); +// return JacksonUtil.fromString(entityDataJson, EntityExportData.class); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } +// } +// +// private EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId) { +// AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, EntitiesVersionControlService.SETTINGS_KEY); +// if (adminSettings != null) { +// try { +// return JacksonUtil.convertValue(adminSettings.getJsonValue(), EntitiesVersionControlSettings.class); +// } catch (Exception e) { +// throw new RuntimeException("Failed to load version control settings!", e); +// } +// } +// return null; +// } +// +// private List listVersions(TenantId tenantId, String branch, String path) { +// try { +// return gitRepositoryService.listVersions(tenantId, branch, path); +// } catch (Exception e) { +// //TODO: analyze and return meaningful exceptions that we can show to the client; +// throw new RuntimeException(e); +// } +// } +// +// private void doInsideLock(PendingCommit commit, Consumer r) { +// var lock = getRepoLock(commit.getTenantId()); +// lock.lock(); +// try { +// checkCommit(commit); +// r.accept(commit); +// } finally { +// lock.unlock(); +// } +// } +// +// private T executeInsideLock(PendingCommit commit, Function c) { +// var lock = getRepoLock(commit.getTenantId()); +// lock.lock(); +// try { +// checkCommit(commit); +// return c.apply(commit); +// } finally { +// lock.unlock(); +// } +// } +// +// private void checkCommit(PendingCommit commit) { +// PendingCommit existing = pendingCommitMap.get(commit.getTenantId()); +// if (existing == null || !existing.getRequestId().equals(commit.getRequestId())) { +// throw new ConcurrentModificationException(); +// } +// } +// +// private String getRelativePath(EntityType entityType, String entityId) { +// String path = entityType.name().toLowerCase(); +// if (entityId != null) { +// path += "/" + entityId + ".json"; +// } +// return path; +// } +// +// private Lock getRepoLock(TenantId tenantId) { +// return tenantRepoLocks.computeIfAbsent(tenantId, t -> new ReentrantLock()); +// } } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java new file mode 100644 index 0000000000..3650f9e113 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java @@ -0,0 +1,37 @@ +/** + * 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.sync.vc; + +import com.google.common.util.concurrent.SettableFuture; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.UUID; + +@Getter +public class PendingGitRequest { + + private final UUID requestId; + private final TenantId tenantId; + private final SettableFuture future; + + public PendingGitRequest(TenantId tenantId) { + this.requestId = UUID.randomUUID(); + this.tenantId = tenantId; + this.future = SettableFuture.create(); + } +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 650f110dd7..1032c79054 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1021,6 +1021,9 @@ queue: stats: enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:60000}" + vc: + topic: "${TB_QUEUE_VC_TOPIC:tb_version_control}" + partitions: "${TB_QUEUE_VC_PARTITIONS:10}" js: # JS Eval request topic request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}" @@ -1115,8 +1118,8 @@ metrics: percentiles: "${METRICS_TIMER_PERCENTILES:0.5}" vc: + thread_pool_size: "${TB_VC_POOL_SIZE:4}" git: - service: "${JS_VC_GIT_SERVICE:local}" # local/remote repos-poll-interval: "${TB_VC_GIT_REPOS_POLL_INTERVAL_SEC:60}" management: diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java index 22953f259a..e2486f3a7e 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java @@ -31,8 +31,9 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; -import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueClusterService; @@ -47,9 +48,11 @@ public interface TbClusterService extends TbQueueClusterService { void pushMsgToCore(ToDeviceActorNotificationMsg msg, TbQueueCallback callback); + void pushMsgToVersionControl(TenantId tenantId, ToVersionControlServiceMsg msg, TbQueueCallback callback); + void pushNotificationToCore(String targetServiceId, FromDeviceRpcResponse response, TbQueueCallback callback); - void pushMsgToRuleEngine(TopicPartitionInfo tpi, UUID msgId, TransportProtos.ToRuleEngineMsg msg, TbQueueCallback callback); + void pushMsgToRuleEngine(TopicPartitionInfo tpi, UUID msgId, ToRuleEngineMsg msg, TbQueueCallback callback); void pushMsgToRuleEngine(TenantId tenantId, EntityId entityId, TbMsg msg, TbQueueCallback callback); diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 50f114856f..cb1a1ab4db 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -618,8 +618,8 @@ message TbSubscriptionUpdateValueListProto { } message TbSubscriptionUpdateTsValue { - int64 ts = 1; - optional string value = 2; + int64 ts = 1; + optional string value = 2; } /** @@ -676,6 +676,95 @@ message EdgeNotificationMsgProto { PostAttributeMsg postAttributesMsg = 12; } +/** + TB Core to Version Control Service + */ +message CommitRequestMsg { + PrepareMsg prepareMsg = 1; + AddMsg addMsg = 2; + DeleteMsg deleteMsg = 3; + PushMsg pushMsg = 4; + AbortMsg abortMsg = 5; +} + +message CommitResponseMsg { + string commitId = 1; + string name = 2; + int32 added = 3; + int32 modified = 4; + int32 removed = 5; +} + +message PrepareMsg { + string commitMsg = 1; + string branchName = 2; +} + +message AddMsg { + string relativePath = 1; + string entityDataJson = 2; +} + +message DeleteMsg { + string relativePath = 1; +} + +message PushMsg { +} + +message AbortMsg { +} + +message ListVersionsRequestMsg { + string branchName = 1; + string entityType = 2; + int64 entityIdMSB = 3; + int64 entityIdLSB = 4; +} + +message ListEntitiesRequestMsg { + string branchName = 1; + string versionId = 2; + string entityType = 3; +} + +message ListBranchesRequestMsg { +} + +message EntityContentRequestMsg { + string versionId = 1; + string entityType = 2; + int64 entityIdMSB = 3; + int64 entityIdLSB = 4; +} + +message EntitiesContentRequestMsg { + string versionId = 1; + string entityType = 2; + int32 offset = 3; + int32 limit = 4; +} + +message ToVersionControlServiceMsg { + string nodeId = 1; + int64 tenantIdMSB = 2; + int64 tenantIdLSB = 3; + int64 requestIdMSB = 4; + int64 requestIdLSB = 5; + CommitRequestMsg commitRequest = 6; + ListVersionsRequestMsg listVersionRequest = 7; + ListEntitiesRequestMsg listEntitiesRequest = 8; + ListBranchesRequestMsg listBranchesRequest = 9; + EntityContentRequestMsg entityContentRequest = 10; + EntitiesContentRequestMsg entitiesContentRequest = 11; +} + +message VersionControlResponseMsg { + int64 requestIdMSB = 1; + int64 requestIdLSB = 2; + CommitResponseMsg commitResponse = 3; +} + /** * Main messages; */ @@ -730,6 +819,7 @@ message ToCoreNotificationMsg { bytes edgeEventUpdateMsg = 4; QueueUpdateMsg queueUpdateMsg = 5; QueueDeleteMsg queueDeleteMsg = 6; + VersionControlResponseMsg vcResponseMsg = 7; } /* Messages that are handled by ThingsBoard RuleEngine Service */ @@ -793,3 +883,5 @@ message ToOtaPackageStateServiceMsg { int64 otaPackageIdLSB = 7; string type = 8; } + + diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceType.java index 1c05ac7f66..7f276e7e3f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/ServiceType.java @@ -17,7 +17,7 @@ package org.thingsboard.server.common.msg.queue; public enum ServiceType { - TB_CORE, TB_RULE_ENGINE, TB_TRANSPORT, JS_EXECUTOR; + TB_CORE, TB_RULE_ENGINE, TB_TRANSPORT, JS_EXECUTOR, TB_VC_EXECUTOR; public static ServiceType of(String serviceType) { return ServiceType.valueOf(serviceType.replace("-", "_").toUpperCase()); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index ccf8b9dd92..e2325be878 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -54,6 +54,10 @@ public class HashPartitionService implements PartitionService { private String coreTopic; @Value("${queue.core.partitions:100}") private Integer corePartitions; + @Value("${queue.vc.topic}") + private String vcTopic; + @Value("${queue.vc.partitions:10}") + private Integer vcPartitions; @Value("${queue.partitions.hash_function_name:murmur3_128}") private String hashFunctionName; @@ -97,6 +101,10 @@ public class HashPartitionService implements PartitionService { partitionSizesMap.put(coreKey, corePartitions); partitionTopicsMap.put(coreKey, coreTopic); + QueueKey vcKey = new QueueKey(ServiceType.TB_VC_EXECUTOR); + partitionSizesMap.put(vcKey, vcPartitions); + partitionTopicsMap.put(vcKey, vcTopic); + List queueRoutingInfoList; String serviceType = serviceInfoProvider.getServiceType(); @@ -401,7 +409,7 @@ public class HashPartitionService implements PartitionService { queueServiceList.computeIfAbsent(key, k -> new ArrayList<>()).add(instance); } }); - } else if (ServiceType.TB_CORE.equals(serviceType)) { + } else if (ServiceType.TB_CORE.equals(serviceType) || ServiceType.TB_VC_EXECUTOR.equals(serviceType)) { queueServiceList.computeIfAbsent(new QueueKey(serviceType), key -> new ArrayList<>()).add(instance); } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java index 4c9194b675..75d0bd9b2d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java @@ -40,6 +40,9 @@ public class TbKafkaTopicConfigs { private String jsExecutorProperties; @Value("${queue.kafka.topic-properties.ota-updates:}") private String fwUpdatesProperties; + @Value("${queue.kafka.topic-properties.version-control:}") + private String vcProperties; + @Getter private Map coreConfigs; @@ -53,6 +56,8 @@ public class TbKafkaTopicConfigs { private Map jsExecutorConfigs; @Getter private Map fwUpdatesConfigs; + @Getter + private Map vcConfigs; @PostConstruct private void init() { @@ -62,6 +67,7 @@ public class TbKafkaTopicConfigs { notificationsConfigs = getConfigs(notificationsProperties); jsExecutorConfigs = getConfigs(jsExecutorProperties); fwUpdatesConfigs = getConfigs(fwUpdatesProperties); + vcConfigs = getConfigs(vcProperties); } private Map getConfigs(String properties) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java index 660173c71d..d02b58aa2b 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -205,6 +206,12 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getOtaPackageTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java index 81736c2b55..89b45e2822 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java @@ -21,6 +21,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -191,6 +192,12 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getOtaPackageTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index fe87fc2886..98c1a8029e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -146,6 +146,12 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE return new InMemoryTbQueueProducer<>(storage, coreSettings.getUsageStatsTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @Scheduled(fixedRateString = "${queue.in_memory.stats.print-interval-ms:60000}") private void printInMemoryStats() { storage.printStats(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index 104c531e12..b24ae700bb 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -51,6 +52,7 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; +import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -58,7 +60,7 @@ import java.util.concurrent.atomic.AtomicLong; @Component @ConditionalOnExpression("'${queue.type:null}'=='kafka' && '${service.type:null}'=='monolith'") -public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { +public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory { private final NotificationsTopicService notificationsTopicService; private final TbKafkaSettings kafkaSettings; @@ -68,6 +70,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi private final TbQueueTransportApiSettings transportApiSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueVersionControlSettings vcSettings; private final TbKafkaConsumerStatsService consumerStatsService; private final TbQueueAdmin coreAdmin; @@ -76,6 +79,8 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; private final TbQueueAdmin fwUpdatesAdmin; + private final TbQueueAdmin vcAdmin; + private final AtomicLong consumerCount = new AtomicLong(); public KafkaMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbKafkaSettings kafkaSettings, @@ -85,6 +90,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi TbQueueTransportApiSettings transportApiSettings, TbQueueTransportNotificationSettings transportNotificationSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueVersionControlSettings vcSettings, TbKafkaConsumerStatsService consumerStatsService, TbKafkaTopicConfigs kafkaTopicConfigs) { this.notificationsTopicService = notificationsTopicService; @@ -95,6 +101,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi this.transportApiSettings = transportApiSettings; this.transportNotificationSettings = transportNotificationSettings; this.jsInvokeSettings = jsInvokeSettings; + this.vcSettings = vcSettings; this.consumerStatsService = consumerStatsService; this.coreAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getCoreConfigs()); @@ -103,6 +110,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi this.transportApiAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getTransportApiConfigs()); this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); this.fwUpdatesAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getFwUpdatesConfigs()); + this.vcAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getVcConfigs()); } @Override @@ -155,6 +163,19 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi return requestBuilder.build(); } + @Override + public TbQueueConsumer> createToVersionControlMsgConsumer() { + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); + consumerBuilder.settings(kafkaSettings); + consumerBuilder.topic(vcSettings.getTopic()); + consumerBuilder.clientId("monolith-vc-consumer-" + serviceInfoProvider.getServiceId()); + consumerBuilder.groupId("monolith-vc-node"); + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + consumerBuilder.admin(vcAdmin); + consumerBuilder.statsService(consumerStatsService); + return consumerBuilder.build(); + } + @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { String queueName = configuration.getName(); @@ -311,6 +332,16 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi return requestBuilder.build(); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + requestBuilder.settings(kafkaSettings); + requestBuilder.clientId("monolith-vc-producer-" + serviceInfoProvider.getServiceId()); + requestBuilder.defaultTopic(vcSettings.getTopic()); + requestBuilder.admin(vcAdmin); + return requestBuilder.build(); + } + @PreDestroy private void destroy() { if (coreAdmin != null) { @@ -331,5 +362,8 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi if (fwUpdatesAdmin != null) { fwUpdatesAdmin.destroy(); } + if (vcAdmin != null) { + vcAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java index 58dec0792a..f476a068d2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java @@ -28,6 +28,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; @@ -50,6 +51,7 @@ import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; +import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; @@ -65,6 +67,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueRuleEngineSettings ruleEngineSettings; private final TbQueueTransportApiSettings transportApiSettings; private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; + private final TbQueueVersionControlSettings vcSettings; private final TbKafkaConsumerStatsService consumerStatsService; private final TbQueueTransportNotificationSettings transportNotificationSettings; @@ -74,6 +77,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { private final TbQueueAdmin transportApiAdmin; private final TbQueueAdmin notificationAdmin; private final TbQueueAdmin fwUpdatesAdmin; + private final TbQueueAdmin vcAdmin; public KafkaTbCoreQueueFactory(NotificationsTopicService notificationsTopicService, TbKafkaSettings kafkaSettings, @@ -82,6 +86,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { TbQueueRuleEngineSettings ruleEngineSettings, TbQueueTransportApiSettings transportApiSettings, TbQueueRemoteJsInvokeSettings jsInvokeSettings, + TbQueueVersionControlSettings vcSettings, TbKafkaConsumerStatsService consumerStatsService, TbQueueTransportNotificationSettings transportNotificationSettings, TbKafkaTopicConfigs kafkaTopicConfigs) { @@ -92,6 +97,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { this.ruleEngineSettings = ruleEngineSettings; this.transportApiSettings = transportApiSettings; this.jsInvokeSettings = jsInvokeSettings; + this.vcSettings = vcSettings; this.consumerStatsService = consumerStatsService; this.transportNotificationSettings = transportNotificationSettings; @@ -101,6 +107,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { this.transportApiAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getTransportApiConfigs()); this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); this.fwUpdatesAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getFwUpdatesConfigs()); + this.vcAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getVcConfigs()); } @Override @@ -282,6 +289,16 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { return requestBuilder.build(); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + requestBuilder.settings(kafkaSettings); + requestBuilder.clientId("tb-core-vc-producer-" + serviceInfoProvider.getServiceId()); + requestBuilder.defaultTopic(vcSettings.getTopic()); + requestBuilder.admin(vcAdmin); + return requestBuilder.build(); + } + @PreDestroy private void destroy() { if (coreAdmin != null) { @@ -302,5 +319,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { if (fwUpdatesAdmin != null) { fwUpdatesAdmin.destroy(); } + if (vcAdmin != null) { + vcAdmin.destroy(); + } } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java new file mode 100644 index 0000000000..598f86d0f4 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java @@ -0,0 +1,116 @@ +/** + * 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.queue.provider; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; +import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.TbQueueProducer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import org.thingsboard.server.queue.kafka.TbKafkaAdmin; +import org.thingsboard.server.queue.kafka.TbKafkaConsumerStatsService; +import org.thingsboard.server.queue.kafka.TbKafkaConsumerTemplate; +import org.thingsboard.server.queue.kafka.TbKafkaProducerTemplate; +import org.thingsboard.server.queue.kafka.TbKafkaSettings; +import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs; +import org.thingsboard.server.queue.settings.TbQueueCoreSettings; +import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; + +import javax.annotation.PreDestroy; + +@Component +@ConditionalOnExpression("'${queue.type:null}'=='kafka' && '${service.type:null}'=='tb-vc-executor'") +public class KafkaTbVersionControlQueueFactory implements TbVersionControlQueueFactory { + + private final TbKafkaSettings kafkaSettings; + private final TbServiceInfoProvider serviceInfoProvider; + private final TbQueueCoreSettings coreSettings; + private final TbQueueVersionControlSettings vcSettings; + private final TbKafkaConsumerStatsService consumerStatsService; + + private final TbQueueAdmin coreAdmin; + private final TbQueueAdmin vcAdmin; + private final TbQueueAdmin notificationAdmin; + + public KafkaTbVersionControlQueueFactory(TbKafkaSettings kafkaSettings, + TbServiceInfoProvider serviceInfoProvider, + TbQueueCoreSettings coreSettings, + TbQueueVersionControlSettings vcSettings, + TbKafkaConsumerStatsService consumerStatsService, + TbKafkaTopicConfigs kafkaTopicConfigs) { + this.kafkaSettings = kafkaSettings; + this.serviceInfoProvider = serviceInfoProvider; + this.coreSettings = coreSettings; + this.vcSettings = vcSettings; + this.consumerStatsService = consumerStatsService; + + this.coreAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getCoreConfigs()); + this.vcAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getVcConfigs()); + this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); + } + + + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + requestBuilder.settings(kafkaSettings); + requestBuilder.clientId("tb-vc-to-core-notifications-" + serviceInfoProvider.getServiceId()); + requestBuilder.defaultTopic(coreSettings.getTopic()); + requestBuilder.admin(notificationAdmin); + return requestBuilder.build(); + } + + @Override + public TbQueueConsumer> createToVersionControlMsgConsumer() { + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); + consumerBuilder.settings(kafkaSettings); + consumerBuilder.topic(vcSettings.getTopic()); + consumerBuilder.clientId("tb-vc-consumer-" + serviceInfoProvider.getServiceId()); + consumerBuilder.groupId("tb-vc-node"); + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + consumerBuilder.admin(vcAdmin); + consumerBuilder.statsService(consumerStatsService); + return consumerBuilder.build(); + } + + @Override + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + requestBuilder.settings(kafkaSettings); + requestBuilder.clientId("tb-vc-us-producer-" + serviceInfoProvider.getServiceId()); + requestBuilder.defaultTopic(coreSettings.getUsageStatsTopic()); + requestBuilder.admin(coreAdmin); + return requestBuilder.build(); + } + + @PreDestroy + private void destroy() { + if (coreAdmin != null) { + coreAdmin.destroy(); + } + if (vcAdmin != null) { + vcAdmin.destroy(); + } + if (notificationAdmin != null) { + notificationAdmin.destroy(); + } + } +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java index aceb9d4f0d..a57e30b655 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -207,6 +208,12 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java index 18a6668581..6cf9aa9a45 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java @@ -21,6 +21,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -191,6 +192,12 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java index 2a724289bb..d4839110e8 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -205,6 +206,12 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getUsageStatsTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java index e728be6085..1dca3ba551 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java @@ -21,6 +21,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -169,6 +170,12 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { return builder.build(); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @Override public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getUsageStatsTopic(), diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java index 88bb0a4045..f7db6379c8 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -204,6 +205,12 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getUsageStatsTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java index e1eb41b2b2..5b471b2830 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java @@ -21,6 +21,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; @@ -191,6 +192,12 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getUsageStatsTopic()); } + @Override + public TbQueueProducer> createVersionControlMsgProducer() { + //TODO: version-control + return null; + } + @PreDestroy private void destroy() { if (coreAdmin != null) { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java index 4debe1e280..aadefa0292 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java @@ -20,6 +20,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; @@ -122,4 +123,11 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory { TbQueueProducer> createTransportApiResponseProducer(); TbQueueRequestTemplate, TbProtoQueueMsg> createRemoteJsRequestTemplate(); + + /** + * Used to push messages to instances of TB Version Control Service + * + * @return + */ + TbQueueProducer> createVersionControlMsgProducer(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java index ef0b0c38e9..ed7de35274 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java @@ -22,6 +22,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -39,6 +40,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { private TbQueueProducer> toRuleEngineNotifications; private TbQueueProducer> toTbCoreNotifications; private TbQueueProducer> toUsageStats; + private TbQueueProducer> toVersionControl; public TbCoreQueueProducerProvider(TbCoreQueueFactory tbQueueProvider) { this.tbQueueProvider = tbQueueProvider; @@ -52,6 +54,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { this.toRuleEngineNotifications = tbQueueProvider.createRuleEngineNotificationsMsgProducer(); this.toTbCoreNotifications = tbQueueProvider.createTbCoreNotificationsMsgProducer(); this.toUsageStats = tbQueueProvider.createToUsageStatsServiceMsgProducer(); + this.toVersionControl = tbQueueProvider.createVersionControlMsgProducer(); } @Override @@ -83,4 +86,9 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } + + @Override + public TbQueueProducer> getTbVersionControlMsgProducer() { + return toVersionControl; + } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java index 19ebb4666e..19046c5a2f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java @@ -21,6 +21,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -70,4 +71,11 @@ public interface TbQueueProducerProvider { * @return */ TbQueueProducer> getTbUsageStatsMsgProducer(); + + /** + * Used to push messages to other instances of TB Core Service + * + * @return + */ + TbQueueProducer> getTbVersionControlMsgProducer(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java index 26f9df069e..c21ae99b8a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.provider; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; @@ -83,4 +84,9 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider { public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } + + @Override + public TbQueueProducer> getTbVersionControlMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Rule Engine!"); + } } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java index 3132ed684f..f9cc139559 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.provider; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; @@ -73,6 +74,11 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider throw new RuntimeException("Not Implemented! Should not be used by Transport!"); } + @Override + public TbQueueProducer> getTbVersionControlMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Transport!"); + } + @Override public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java new file mode 100644 index 0000000000..c8ffc1da0d --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java @@ -0,0 +1,84 @@ +/** + * 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.queue.provider; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.queue.TbQueueProducer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; + +import javax.annotation.PostConstruct; + +@Service +@ConditionalOnExpression("'${service.type:null}'=='tb-vc-executor'") +public class TbVersionControlProducerProvider implements TbQueueProducerProvider { + + private final TbVersionControlQueueFactory tbQueueProvider; + private TbQueueProducer> toTbCoreNotifications; + private TbQueueProducer> toUsageStats; + + public TbVersionControlProducerProvider(TbVersionControlQueueFactory tbQueueProvider) { + this.tbQueueProvider = tbQueueProvider; + } + + @PostConstruct + public void init() { + this.toTbCoreNotifications = tbQueueProvider.createTbCoreNotificationsMsgProducer(); + this.toUsageStats = tbQueueProvider.createToUsageStatsServiceMsgProducer(); + } + + @Override + public TbQueueProducer> getTransportNotificationsMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!"); + } + + @Override + public TbQueueProducer> getRuleEngineMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!"); + } + + @Override + public TbQueueProducer> getTbCoreMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!"); + } + + @Override + public TbQueueProducer> getRuleEngineNotificationsMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!"); + } + + @Override + public TbQueueProducer> getTbCoreNotificationsMsgProducer() { + return toTbCoreNotifications; + } + + @Override + public TbQueueProducer> getTbVersionControlMsgProducer() { + throw new RuntimeException("Not Implemented! Should not be used by Version Control Service!"); + } + + @Override + public TbQueueProducer> getTbUsageStatsMsgProducer() { + return toUsageStats; + } +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlQueueFactory.java new file mode 100644 index 0000000000..70b16afc68 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlQueueFactory.java @@ -0,0 +1,44 @@ +/** + * 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.queue.provider; + +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.TbQueueProducer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; + +/** + * Responsible for initialization of various Producers and Consumers used by TB Version Control Node. + * Implementation Depends on the queue queue.type from yml or TB_QUEUE_TYPE environment variable + */ +public interface TbVersionControlQueueFactory extends TbUsageStatsClientQueueFactory { + + /** + * Used to push notifications to other instances of TB Core Service + * + * @return + */ + TbQueueProducer> createTbCoreNotificationsMsgProducer(); + + /** + * Used to consume messages from TB Core Service + * + * @return + */ + TbQueueConsumer> createToVersionControlMsgConsumer(); + +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueVersionControlSettings.java b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueVersionControlSettings.java new file mode 100644 index 0000000000..e7f0ce2259 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueVersionControlSettings.java @@ -0,0 +1,34 @@ +/** + * 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.queue.settings; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class TbQueueVersionControlSettings { + + @Value("${queue.vc.topic:tb_version_control}") + private String topic; + + @Value("${queue.vc.usage-stats-topic:tb_usage_stats}") + private String usageStatsTopic; + + @Value("${queue.vc.partitions:10}") + private int partitions; +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbVersionControlComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbVersionControlComponent.java new file mode 100644 index 0000000000..e72fe60b6e --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbVersionControlComponent.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-vc-executor'") +public @interface TbVersionControlComponent { +} diff --git a/common/version-control/pom.xml b/common/version-control/pom.xml index a8d775bcdc..7b46f7ba72 100644 --- a/common/version-control/pom.xml +++ b/common/version-control/pom.xml @@ -86,21 +86,6 @@ org.eclipse.jgit org.eclipse.jgit - - io.grpc - grpc-netty-shaded - provided - - - io.grpc - grpc-protobuf - provided - - - io.grpc - grpc-stub - provided - org.eclipse.jgit org.eclipse.jgit.ssh.apache @@ -126,15 +111,6 @@ - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - - - - thingsboard-repo-deploy diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java index f28584c418..56349cf8a5 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java @@ -16,15 +16,12 @@ package org.thingsboard.server.service.sync.vc; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.EntityVersion; -import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; -import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; import java.util.List; @@ -36,14 +33,6 @@ public interface GitVersionControlService { void clearRepository(TenantId tenantId); - PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request); - - void addToCommit(PendingCommit commit, EntityExportData> entityData); - - void deleteAll(PendingCommit pendingCommit, EntityType entityType); - - VersionCreationResult push(PendingCommit commit); - List listVersions(TenantId tenantId, String branch); List listVersions(TenantId tenantId, String branch, EntityType entityType); diff --git a/common/version-control/src/main/proto/vc.proto b/common/version-control/src/main/proto/vc.proto deleted file mode 100644 index e8c7e09384..0000000000 --- a/common/version-control/src/main/proto/vc.proto +++ /dev/null @@ -1,71 +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. - */ -syntax = "proto3"; - -option java_package = "org.thingsboard.server.gen.vc.v1"; -option java_multiple_files = true; -option java_outer_classname = "EdgeProtos"; - -package vc; - -// Interface exported by the ThingsBoard Core. -service TbGitRpcService { - - rpc commit(stream CommitRequestMsg) returns (CommitResponseMsg) {} - -} - - -/** - * Data Structures; - */ -message CommitRequestMsg { - string txId = 1; - PrepareMsg prepareMsg = 2; - AddMsg addMsg = 3; - DeleteMsg deleteMsg = 4; - PushMsg pushMsg = 5; - AbortMsg abortMsg = 6; -} - -message CommitResponseMsg { - string id = 1; - string name = 2; - int32 added = 3; - int32 modified = 4; - int32 removed = 5; -} - -message PrepareMsg { - string tenantId = 1; - string commitMsg = 2; - string branchName = 3; -} - -message AddMsg { - string relativePath = 1; - string entityDataJson = 2; -} - -message DeleteMsg { - string relativePath = 1; -} - -message PushMsg { -} - -message AbortMsg { -} \ No newline at end of file From 4472bd7f7c3d70f7a75a3b26bd0a81769789ce6b Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 23 May 2022 12:50:59 +0300 Subject: [PATCH 57/58] Initial implementation of the ClusterVersionControlService --- .../server/actors/ActorSystemContext.java | 2 +- .../DeviceProfileMsgConstructor.java | 2 +- .../queue/DefaultTbClusterService.java | 3 +- .../queue/DefaultTbCoreConsumerService.java | 13 +- .../DefaultTbRuleEngineConsumerService.java | 3 +- .../processing/AbstractConsumerService.java | 2 +- .../DefaultEntitiesVersionControlService.java | 63 ++--- .../DefaultGitVersionControlQueueService.java | 79 ++++++- .../vc/EntitiesVersionControlService.java | 5 +- .../vc/GitVersionControlQueueService.java | 9 + .../service/sync/vc/PendingGitRequest.java | 1 - .../service/sync/vc/VoidGitRequest.java | 29 +++ .../transport/DefaultTransportApiService.java | 2 +- .../src/main/resources/thingsboard.yml | 2 + common/cluster-api/src/main/proto/queue.proto | 24 +- .../vc/EntitiesVersionControlSettings.java | 7 +- common/queue/pom.xml | 4 + .../InMemoryMonolithQueueFactory.java | 13 +- .../util/DataDecodingEncodingService.java | 2 +- .../queue}/util/ProtoWithFSTService.java | 3 +- .../service/ProtoTransportEntityService.java | 5 +- common/transport/transport-api/pom.xml | 4 - .../DefaultTransportDeviceProfileCache.java | 2 +- .../DefaultTransportResourceCache.java | 2 +- .../service/DefaultTransportService.java | 2 +- .../DefaultTransportTenantProfileCache.java | 2 +- common/version-control/pom.xml | 12 +- .../sync/vc/ClusterVersionControlService.java | 22 ++ .../DefaultClusterVersionControlService.java | 219 ++++++++++++++++++ .../sync/vc/GitVersionControlService.java | 52 ----- .../sync/vc/VersionControlRequestCtx.java | 49 ++++ 31 files changed, 505 insertions(+), 134 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java rename common/{transport/transport-api/src/main/java/org/thingsboard/server/common/transport => queue/src/main/java/org/thingsboard/server/queue}/util/DataDecodingEncodingService.java (93%) rename common/{transport/transport-api/src/main/java/org/thingsboard/server/common/transport => queue/src/main/java/org/thingsboard/server/queue}/util/ProtoWithFSTService.java (93%) create mode 100644 common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/ClusterVersionControlService.java create mode 100644 common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java delete mode 100644 common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java create mode 100644 common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/VersionControlRequestCtx.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 500ad60524..733cf75e64 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -48,7 +48,7 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.tools.TbRateLimits; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.audit.AuditLogService; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java index 77dc121e38..7943ec0595 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java @@ -20,7 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.id.DeviceProfileId; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.queue.util.TbCoreComponent; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 4a52ea2287..6b475f5a5a 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -53,7 +53,7 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; @@ -140,6 +140,7 @@ public class DefaultTbClusterService implements TbClusterService { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_VC_EXECUTOR, tenantId, tenantId); log.trace("PUSHING msg: {} to:{}", msg, tpi); producerProvider.getTbVersionControlMsgProducer().send(tpi, new TbProtoQueueMsg<>(tenantId.getId(), msg), callback); + //TODO: ashvayka toCoreMsgs.incrementAndGet(); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index bec0dceed3..4cf7f86097 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -36,7 +36,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; import org.thingsboard.server.common.stats.StatsFactory; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto; @@ -74,6 +74,8 @@ import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.subscription.SubscriptionManagerService; import org.thingsboard.server.service.subscription.TbLocalSubscriptionService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; +import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; +import org.thingsboard.server.service.sync.vc.GitVersionControlQueueService; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; import javax.annotation.PostConstruct; @@ -116,6 +118,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> usageStatsConsumer; private final TbQueueConsumer> firmwareStatesConsumer; @@ -137,7 +140,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService void registerAndSend(PendingGitRequest request, Function enrichFunction, TbQueueCallback callback) { - if (!request.getFuture().isDone()) { - pendingRequestMap.putIfAbsent(request.getRequestId(), request); - clusterService.pushMsgToVersionControl(request.getTenantId(), enrichFunction.apply(newRequestProto(request)), callback); - } else { - throw new RuntimeException("Future is already done!"); - } - } - @Override public ListenableFuture getEntity(TenantId tenantId, String versionId, EntityId entityId) { EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId); @@ -218,6 +214,15 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu // } } + private void registerAndSend(PendingGitRequest request, Function enrichFunction, TbQueueCallback callback) { + if (!request.getFuture().isDone()) { + pendingRequestMap.putIfAbsent(request.getRequestId(), request); + clusterService.pushMsgToVersionControl(request.getTenantId(), enrichFunction.apply(newRequestProto(request)), callback); + } else { + throw new RuntimeException("Future is already done!"); + } + } + @Override public ListenableFuture> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) { EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType); @@ -233,6 +238,56 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu return request.getFuture(); } + @Override + public ListenableFuture initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { + VoidGitRequest request = new VoidGitRequest(tenantId); + + registerAndSend(request, builder -> builder.setInitRepositoryRequest(GenericRepositoryRequestMsg.newBuilder().build()).build() + , wrap(request.getFuture())); + + return request.getFuture(); + } + + @Override + public ListenableFuture testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { + VoidGitRequest request = new VoidGitRequest(tenantId); + + registerAndSend(request, builder -> builder.setTestRepositoryRequest(GenericRepositoryRequestMsg.newBuilder().build()).build() + , wrap(request.getFuture())); + + return request.getFuture(); + } + + @Override + public ListenableFuture clearRepository(TenantId tenantId) { + VoidGitRequest request = new VoidGitRequest(tenantId); + + registerAndSend(request, builder -> builder.setClearRepositoryRequest(GenericRepositoryRequestMsg.newBuilder().build()).build() + , wrap(request.getFuture())); + + return request.getFuture(); + } + + @Override + public void processResponse(VersionControlResponseMsg vcResponseMsg) { + UUID requestId = new UUID(vcResponseMsg.getRequestIdMSB(), vcResponseMsg.getRequestIdLSB()); + PendingGitRequest request = pendingRequestMap.get(requestId); + if (request == null) { + log.debug("[{}] received stale response: {}", requestId, vcResponseMsg); + return; + } else { + log.debug("[{}] processing response: {}", requestId, vcResponseMsg); + } + var future = request.getFuture(); + if (!StringUtils.isEmpty(vcResponseMsg.getError())) { + future.setException(new RuntimeException(vcResponseMsg.getError())); + } else { + if (vcResponseMsg.hasGenericResponse()) { + future.set(null); + } + } + } + private static TbQueueCallback wrap(SettableFuture future) { return new TbQueueCallback() { @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java index 02afafedad..bb42e44f82 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadReques import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; import java.util.List; +import java.util.concurrent.ExecutionException; public interface EntitiesVersionControlService { @@ -57,8 +58,8 @@ public interface EntitiesVersionControlService { EntitiesVersionControlSettings saveVersionControlSettings(TenantId tenantId, EntitiesVersionControlSettings versionControlSettings); - void deleteVersionControlSettings(TenantId tenantId); + void deleteVersionControlSettings(TenantId tenantId) throws Exception; - void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws ThingsboardException; + void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception; } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java index e7b7171ea0..f09b383d87 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java @@ -21,10 +21,12 @@ import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.sync.ie.EntityExportData; +import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.EntityVersion; import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; +import org.thingsboard.server.gen.transport.TransportProtos.VersionControlResponseMsg; import java.util.List; @@ -54,4 +56,11 @@ public interface GitVersionControlQueueService { ListenableFuture> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit); + ListenableFuture initRepository(TenantId tenantId, EntitiesVersionControlSettings settings); + + ListenableFuture testRepository(TenantId tenantId, EntitiesVersionControlSettings settings); + + ListenableFuture clearRepository(TenantId tenantId); + + void processResponse(VersionControlResponseMsg vcResponseMsg); } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java index 3650f9e113..09bc272828 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java @@ -17,7 +17,6 @@ package org.thingsboard.server.service.sync.vc; import com.google.common.util.concurrent.SettableFuture; import lombok.Getter; -import lombok.RequiredArgsConstructor; import org.thingsboard.server.common.data.id.TenantId; import java.util.UUID; diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java new file mode 100644 index 0000000000..d829960ab4 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java @@ -0,0 +1,29 @@ +/** + * 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.sync.vc; + +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.vc.EntityVersion; + +import java.util.List; + +public class VoidGitRequest extends PendingGitRequest { + + public VoidGitRequest(TenantId tenantId) { + super(tenantId); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 6c4adfc5ae..f8b42ecc1e 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -65,7 +65,7 @@ import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProvisionService; import org.thingsboard.server.dao.device.DeviceService; diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 1032c79054..3fb48d2789 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1024,6 +1024,8 @@ queue: vc: topic: "${TB_QUEUE_VC_TOPIC:tb_version_control}" partitions: "${TB_QUEUE_VC_PARTITIONS:10}" + poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}" + pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:2000}" js: # JS Eval request topic request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}" diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index cb1a1ab4db..7a5030277e 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -745,24 +745,34 @@ message EntitiesContentRequestMsg { int32 limit = 4; } +message GenericRepositoryRequestMsg {} + +message GenericRepositoryResponseMsg {} + message ToVersionControlServiceMsg { string nodeId = 1; int64 tenantIdMSB = 2; int64 tenantIdLSB = 3; int64 requestIdMSB = 4; int64 requestIdLSB = 5; - CommitRequestMsg commitRequest = 6; - ListVersionsRequestMsg listVersionRequest = 7; - ListEntitiesRequestMsg listEntitiesRequest = 8; - ListBranchesRequestMsg listBranchesRequest = 9; - EntityContentRequestMsg entityContentRequest = 10; - EntitiesContentRequestMsg entitiesContentRequest = 11; + bytes vcSettings = 6; + GenericRepositoryRequestMsg initRepositoryRequest = 7; + GenericRepositoryRequestMsg testRepositoryRequest = 8; + GenericRepositoryRequestMsg clearRepositoryRequest = 9; + CommitRequestMsg commitRequest = 10; + ListVersionsRequestMsg listVersionRequest = 11; + ListEntitiesRequestMsg listEntitiesRequest = 12; + ListBranchesRequestMsg listBranchesRequest = 13; + EntityContentRequestMsg entityContentRequest = 14; + EntitiesContentRequestMsg entitiesContentRequest = 15; } message VersionControlResponseMsg { int64 requestIdMSB = 1; int64 requestIdLSB = 2; - CommitResponseMsg commitResponse = 3; + string error = 3; + GenericRepositoryResponseMsg genericResponse = 4; + CommitResponseMsg commitResponse = 5; } /** diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java index 4fdff1f413..bc098fbe1f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java @@ -16,8 +16,13 @@ package org.thingsboard.server.common.data.sync.vc; import lombok.Data; + +import java.io.Serializable; + @Data -public class EntitiesVersionControlSettings { +public class EntitiesVersionControlSettings implements Serializable { + private static final long serialVersionUID = -3211552851889198721L; + private String repositoryUri; private VersionControlAuthMethod authMethod; private String username; diff --git a/common/queue/pom.xml b/common/queue/pom.xml index e2197d566f..a625ec6e93 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -120,6 +120,10 @@ com.google.protobuf protobuf-java-util + + de.ruedigermoeller + fst + org.apache.curator curator-recipes diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index 98c1a8029e..b6b89fcc2f 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -37,28 +37,32 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings; import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; +import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; @Slf4j @Component @ConditionalOnExpression("'${queue.type:null}'=='in-memory' && '${service.type:null}'=='monolith'") -public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory { +public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory { private final NotificationsTopicService notificationsTopicService; private final TbQueueCoreSettings coreSettings; private final TbServiceInfoProvider serviceInfoProvider; private final TbQueueRuleEngineSettings ruleEngineSettings; + private final TbQueueVersionControlSettings vcSettings; private final TbQueueTransportApiSettings transportApiSettings; private final TbQueueTransportNotificationSettings transportNotificationSettings; private final InMemoryStorage storage; public InMemoryMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings, TbQueueRuleEngineSettings ruleEngineSettings, + TbQueueVersionControlSettings vcSettings, TbServiceInfoProvider serviceInfoProvider, TbQueueTransportApiSettings transportApiSettings, TbQueueTransportNotificationSettings transportNotificationSettings, InMemoryStorage storage) { this.notificationsTopicService = notificationsTopicService; this.coreSettings = coreSettings; + this.vcSettings = vcSettings; this.serviceInfoProvider = serviceInfoProvider; this.ruleEngineSettings = ruleEngineSettings; this.transportApiSettings = transportApiSettings; @@ -91,6 +95,11 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE return new InMemoryTbQueueProducer<>(storage, coreSettings.getTopic()); } + @Override + public TbQueueConsumer> createToVersionControlMsgConsumer() { + return new InMemoryTbQueueConsumer<>(storage, vcSettings.getTopic()); + } + @Override public TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration) { return new InMemoryTbQueueConsumer<>(storage, configuration.getTopic()); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/DataDecodingEncodingService.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/DataDecodingEncodingService.java similarity index 93% rename from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/DataDecodingEncodingService.java rename to common/queue/src/main/java/org/thingsboard/server/queue/util/DataDecodingEncodingService.java index ed0572e8e5..8ebcc39cab 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/DataDecodingEncodingService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/DataDecodingEncodingService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.transport.util; +package org.thingsboard.server.queue.util; import java.util.Optional; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/ProtoWithFSTService.java similarity index 93% rename from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java rename to common/queue/src/main/java/org/thingsboard/server/queue/util/ProtoWithFSTService.java index 1c5eec383c..f1c55973db 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/ProtoWithFSTService.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.transport.util; +package org.thingsboard.server.queue.util; import lombok.extern.slf4j.Slf4j; import org.nustaq.serialization.FSTConfiguration; import org.springframework.stereotype.Service; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import java.util.Optional; diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/ProtoTransportEntityService.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/ProtoTransportEntityService.java index c75de25267..a10c3e4969 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/ProtoTransportEntityService.java +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/ProtoTransportEntityService.java @@ -24,14 +24,11 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbSnmpTransportComponent; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; @TbSnmpTransportComponent @Service diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 8b3f9feb22..51373e2a4a 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -64,10 +64,6 @@ com.google.code.gson gson - - de.ruedigermoeller - fst - org.slf4j slf4j-api diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java index b79306199f..2b0f73343d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java @@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.transport.TransportDeviceProfileCache; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbTransportComponent; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java index 666941b143..b4187432e8 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.TransportResourceCache; import org.thingsboard.server.common.transport.TransportService; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbTransportComponent; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 5b29d3c3ff..3256039e9a 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -69,7 +69,7 @@ import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGateway import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.limits.TransportRateLimitService; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportTenantProfileCache.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportTenantProfileCache.java index 4cfefb7a6f..bb7f8f3f4d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportTenantProfileCache.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportTenantProfileCache.java @@ -29,7 +29,7 @@ import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportTenantProfileCache; import org.thingsboard.server.common.transport.limits.TransportRateLimitService; import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbTransportComponent; diff --git a/common/version-control/pom.xml b/common/version-control/pom.xml index 7b46f7ba72..294141db8f 100644 --- a/common/version-control/pom.xml +++ b/common/version-control/pom.xml @@ -36,6 +36,14 @@ + + org.thingsboard.common + data + + + org.thingsboard.common + queue + org.springframework spring-core @@ -105,10 +113,6 @@ awaitility test - - org.thingsboard.common - data - diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/ClusterVersionControlService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/ClusterVersionControlService.java new file mode 100644 index 0000000000..fc134e1850 --- /dev/null +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/ClusterVersionControlService.java @@ -0,0 +1,22 @@ +/** + * 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.sync.vc; + +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; +import org.springframework.context.ApplicationListener; + +public interface ClusterVersionControlService extends ApplicationListener { +} diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java new file mode 100644 index 0000000000..73089acdf5 --- /dev/null +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java @@ -0,0 +1,219 @@ +/** + * 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.sync.vc; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; +import org.thingsboard.server.queue.TbQueueCallback; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.TbQueueMsgMetadata; +import org.thingsboard.server.queue.TbQueueProducer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.NotificationsTopicService; +import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; +import org.thingsboard.server.queue.provider.TbVersionControlQueueFactory; +import org.thingsboard.server.queue.util.DataDecodingEncodingService; +import org.thingsboard.server.queue.util.TbVersionControlComponent; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +@TbVersionControlComponent +@Service +@RequiredArgsConstructor +public class DefaultClusterVersionControlService extends TbApplicationEventListener implements ClusterVersionControlService { + + private final TbServiceInfoProvider serviceInfoProvider; + private final TbVersionControlQueueFactory queueFactory; + private final DataDecodingEncodingService encodingService; + private final GitRepositoryService vcService; + private final NotificationsTopicService notificationsTopicService; + + private volatile ExecutorService consumerExecutor; + private volatile TbQueueConsumer> consumer; + private volatile TbQueueProducer> producer; + private volatile boolean stopped = false; + + @Value("${queue.vc.poll-interval:25}") + private long pollDuration; + @Value("${queue.vc.pack-processing-timeout:60000}") + private long packProcessingTimeout; + + @PostConstruct + public void init() { + consumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("vc-consumer")); + producer = queueFactory.createTbCoreNotificationsMsgProducer(); + consumer = queueFactory.createToVersionControlMsgConsumer(); + } + + @PreDestroy + public void stop() { + stopped = true; + if (consumer != null) { + consumer.unsubscribe(); + } + if (consumerExecutor != null) { + consumerExecutor.shutdownNow(); + } + } + + @Override + protected void onTbApplicationEvent(PartitionChangeEvent event) { + //TODO: cleanup repositories that we no longer manage in this node. + consumer.subscribe(event.getPartitions()); + } + + @EventListener(ApplicationReadyEvent.class) + @Order(value = 2) + public void onApplicationEvent(ApplicationReadyEvent event) { + consumerExecutor.execute(() -> consumerLoop(consumer)); + } + + void consumerLoop(TbQueueConsumer> consumer) { + while (!stopped && !consumer.isStopped()) { + try { + List> msgs = consumer.poll(pollDuration); + if (msgs.isEmpty()) { + continue; + } + for (TbProtoQueueMsg msgWrapper : msgs) { + ToVersionControlServiceMsg msg = msgWrapper.getValue(); + if (msg.hasClearRepositoryRequest()) { + handleClearRepositoryCommand(new VersionControlRequestCtx(msg, null)); + } else { + VersionControlRequestCtx ctx = new VersionControlRequestCtx(msg, getEntitiesVersionControlSettings(msg)); + if (msg.hasTestRepositoryRequest()) { + handleTestRepositoryCommand(ctx); + } else if (msg.hasInitRepositoryRequest()) { + handleInitRepositoryCommand(ctx); + } + } + } +// ConcurrentMap> pendingMap = msgs.stream().collect( +// Collectors.toConcurrentMap(s -> UUID.randomUUID(), Function.identity())); +// CountDownLatch processingTimeoutLatch = new CountDownLatch(1); +// TbPackProcessingContext> ctx = new TbPackProcessingContext<>( +// processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>()); +// pendingMap.forEach((id, msg) -> { +// log.trace("[{}] Creating downlink callback for message: {}", id, msg.getValue()); +// TbCallback callback = new TbPackCallback<>(id, ctx); +// try { +// handleDownlink(id, msg, callback); +// } catch (Throwable e) { +// log.warn("[{}] Failed to process notification: {}", id, msg, e); +// callback.onFailure(e); +// } +// }); +// if (!processingTimeoutLatch.await(processingTimeout, TimeUnit.MILLISECONDS)) { +// ctx.getAckMap().forEach((id, msg) -> log.warn("[{}] Timeout to process downlink: {}", id, msg.getValue())); +// ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process downlink: {}", id, msg.getValue())); +// } + consumer.commit(); + } catch (Exception e) { + if (!stopped) { + log.warn("Failed to obtain version control requests from queue.", e); + try { + Thread.sleep(pollDuration); + } catch (InterruptedException e2) { + log.trace("Failed to wait until the server has capacity to handle new version control messages", e2); + } + } + } + } + log.info("TB Version Control request consumer stopped."); + } + + private void handleClearRepositoryCommand(VersionControlRequestCtx ctx) { + try { + vcService.clearRepository(ctx.getTenantId()); + reply(ctx, Optional.empty()); + } catch (Exception e) { + log.debug("[{}] Failed to connect to the repository: ", ctx, e); + reply(ctx, Optional.of(e)); + } + } + + private void handleInitRepositoryCommand(VersionControlRequestCtx ctx) { + try { + vcService.initRepository(ctx.getTenantId(), ctx.getSettings()); + reply(ctx, Optional.empty()); + } catch (Exception e) { + log.debug("[{}] Failed to connect to the repository: ", ctx, e); + reply(ctx, Optional.of(e)); + } + } + + + private void handleTestRepositoryCommand(VersionControlRequestCtx ctx) { + try { + vcService.testRepository(ctx.getTenantId(), ctx.getSettings()); + reply(ctx, Optional.empty()); + } catch (Exception e) { + log.debug("[{}] Failed to connect to the repository: ", ctx, e); + reply(ctx, Optional.of(e)); + } + } + + private void reply(VersionControlRequestCtx ctx, Optional e) { + TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, ctx.getNodeId()); + TransportProtos.VersionControlResponseMsg.Builder builder = TransportProtos.VersionControlResponseMsg.newBuilder() + .setRequestIdMSB(ctx.getRequestId().getMostSignificantBits()) + .setRequestIdLSB(ctx.getRequestId().getLeastSignificantBits()); + if (e.isPresent()) { + builder.setError(e.get().getMessage()); + } else { + builder.setGenericResponse(TransportProtos.GenericRepositoryResponseMsg.newBuilder().build()); + } + ToCoreNotificationMsg msg = ToCoreNotificationMsg.newBuilder().setVcResponseMsg(builder).build(); + log.trace("PUSHING msg: {} to: {}", msg, tpi); + producer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null); + } + + private EntitiesVersionControlSettings getEntitiesVersionControlSettings(ToVersionControlServiceMsg msg) { + Optional settingsOpt = encodingService.decode(msg.getVcSettings().toByteArray()); + if (settingsOpt.isPresent()) { + return settingsOpt.get(); + } else { + log.warn("Failed to parse VC settings: {}", msg.getVcSettings()); + throw new RuntimeException("Failed to parse vc settings!"); + } + } + +} diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java deleted file mode 100644 index 56349cf8a5..0000000000 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java +++ /dev/null @@ -1,52 +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.sync.vc; - -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.sync.ie.EntityExportData; -import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; -import org.thingsboard.server.common.data.sync.vc.EntityVersion; -import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; - -import java.util.List; - -public interface GitVersionControlService { - - void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings); - - void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings); - - void clearRepository(TenantId tenantId); - - List listVersions(TenantId tenantId, String branch); - - List listVersions(TenantId tenantId, String branch, EntityType entityType); - - List listVersions(TenantId tenantId, String branch, EntityId entityId); - - List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType); - - List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId); - - List listBranches(TenantId tenantId); - - EntityExportData getEntity(TenantId tenantId, String versionId, EntityId entityId); - - List> getEntities(TenantId tenantId, String branch, String versionId, EntityType entityType, int offset, int limit); - -} diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/VersionControlRequestCtx.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/VersionControlRequestCtx.java new file mode 100644 index 0000000000..6541a2978a --- /dev/null +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/VersionControlRequestCtx.java @@ -0,0 +1,49 @@ +/** + * 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.sync.vc; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; +import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; + +import java.util.UUID; + +@RequiredArgsConstructor +@Data +public class VersionControlRequestCtx { + private final String nodeId; + private final UUID requestId; + private final TenantId tenantId; + private final EntitiesVersionControlSettings settings; + + public VersionControlRequestCtx(ToVersionControlServiceMsg msg, EntitiesVersionControlSettings settings) { + this.nodeId = msg.getNodeId(); + this.requestId = new UUID(msg.getRequestIdMSB(), msg.getRequestIdLSB()); + this.tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); + this.settings = settings; + } + + @Override + public String toString() { + return "VersionControlRequestCtx{" + + "nodeId='" + nodeId + '\'' + + ", requestId=" + requestId + + ", tenantId=" + tenantId + + '}'; + } +} From 1065fd9fbebec782ed7fddc268f26d712cd10917 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 24 May 2022 11:38:03 +0300 Subject: [PATCH 58/58] Implementation of the API --- .../DefaultGitVersionControlQueueService.java | 49 ++- .../vc/LocalGitVersionControlService.java | 290 ------------------ .../service/sync/vc/PendingGitRequest.java | 4 +- common/cluster-api/src/main/proto/queue.proto | 37 +++ .../data/sync/vc/VersionedEntityInfo.java | 6 + .../DefaultClusterVersionControlService.java | 109 ++++++- .../sync/vc/DefaultGitRepositoryService.java | 8 +- .../service/sync/vc/GitRepositoryService.java | 4 +- 8 files changed, 188 insertions(+), 319 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java index 7ffcbb9c14..0d3f2a4431 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java @@ -21,17 +21,16 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.google.protobuf.ByteString; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; @@ -61,6 +60,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; +import java.util.stream.Collectors; @TbCoreComponent @Service @@ -209,6 +209,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu } @Override + @SuppressWarnings("rawtypes") public ListenableFuture getEntity(TenantId tenantId, String versionId, EntityId entityId) { EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId); registerAndSend(request, builder -> builder.setEntityContentRequest(EntityContentRequestMsg.newBuilder() @@ -218,14 +219,6 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu .setEntityIdLSB(entityId.getId().getLeastSignificantBits())).build() , wrap(request.getFuture())); return request.getFuture(); -// try { -// String entityDataJson = gitRepositoryService.getFileContentAtCommit(tenantId, -// getRelativePath(entityId.getEntityType(), entityId.getId().toString()), versionId); -// return JacksonUtil.fromString(entityDataJson, EntityExportData.class); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } } private void registerAndSend(PendingGitRequest request, @@ -237,13 +230,16 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu Function enrichFunction, EntitiesVersionControlSettings settings, TbQueueCallback callback) { if (!request.getFuture().isDone()) { pendingRequestMap.putIfAbsent(request.getRequestId(), request); - clusterService.pushMsgToVersionControl(request.getTenantId(), enrichFunction.apply(newRequestProto(request, settings)), callback); + var requestBody = enrichFunction.apply(newRequestProto(request, settings)); + log.trace("[{}][{}] PUSHING request: {}", request.getTenantId(), request.getRequestId(), requestBody); + clusterService.pushMsgToVersionControl(request.getTenantId(), requestBody, callback); } else { throw new RuntimeException("Future is already done!"); } } @Override + @SuppressWarnings("rawtypes") public ListenableFuture> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) { EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType); @@ -313,10 +309,41 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu commitResult.setRemoved(commitResponse.getRemoved()); commitResult.setModified(commitResponse.getModified()); ((CommitGitRequest) request).getFuture().set(commitResult); + } else if (vcResponseMsg.hasListBranchesResponse()) { + var listBranchesResponse = vcResponseMsg.getListBranchesResponse(); + ((ListBranchesGitRequest) request).getFuture().set(listBranchesResponse.getBranchesList()); + } else if (vcResponseMsg.hasListEntitiesResponse()) { + var listEntitiesResponse = vcResponseMsg.getListEntitiesResponse(); + ((ListEntitiesGitRequest) request).getFuture().set( + listEntitiesResponse.getEntitiesList().stream().map(this::getVersionedEntityInfo).collect(Collectors.toList())); + } else if (vcResponseMsg.hasListVersionsResponse()) { + var listVersionsResponse = vcResponseMsg.getListVersionsResponse(); + ((ListVersionsGitRequest) request).getFuture().set( + listVersionsResponse.getVersionsList().stream().map(this::getEntityVersion).collect(Collectors.toList())); + } else if (vcResponseMsg.hasEntityContentResponse()) { + var data = vcResponseMsg.getEntityContentResponse().getData(); + ((EntityContentGitRequest) request).getFuture().set(toData(data)); + } else if (vcResponseMsg.hasEntitiesContentResponse()) { + var dataList = vcResponseMsg.getEntitiesContentResponse().getDataList(); + ((EntitiesContentGitRequest) request).getFuture() + .set(dataList.stream().map(this::toData).collect(Collectors.toList())); } } } + private EntityVersion getEntityVersion(TransportProtos.EntityVersionProto proto) { + return new EntityVersion(proto.getId(), proto.getName()); + } + + private VersionedEntityInfo getVersionedEntityInfo(TransportProtos.VersionedEntityInfoProto proto) { + return new VersionedEntityInfo(EntityIdFactory.getByTypeAndUuid(proto.getEntityType(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB()))); + } + + @SuppressWarnings("rawtypes") + private EntityExportData toData(String data) { + return JacksonUtil.fromString(data, EntityExportData.class); + } + private static TbQueueCallback wrap(SettableFuture future) { return new TbQueueCallback() { @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java deleted file mode 100644 index d995472531..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/LocalGitVersionControlService.java +++ /dev/null @@ -1,290 +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.sync.vc; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.SerializationFeature; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Service; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.AdminSettings; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.ExportableEntity; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.sync.ie.EntityExportData; -import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; -import org.thingsboard.server.common.data.sync.vc.EntityVersion; -import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; -import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; -import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; -import org.thingsboard.server.dao.DaoUtil; -import org.thingsboard.server.dao.settings.AdminSettingsService; -import org.thingsboard.server.dao.tenant.TenantDao; -import org.thingsboard.server.queue.util.AfterStartUp; - -import java.io.IOException; -import java.util.ConcurrentModificationException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; - -@Slf4j -@RequiredArgsConstructor -@Service -@ConditionalOnProperty(prefix = "vc", value = "git.service", havingValue = "local", matchIfMissing = true) -public class LocalGitVersionControlService { - - private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT); - private final GitRepositoryService gitRepositoryService; - private final TenantDao tenantDao; - private final AdminSettingsService adminSettingsService; - private final ConcurrentMap tenantRepoLocks = new ConcurrentHashMap<>(); - private final Map pendingCommitMap = new HashMap<>(); -// -// @AfterStartUp -// public void init() { -// DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> { -// EntitiesVersionControlSettings settings = getVersionControlSettings(tenantId); -// if (settings != null) { -// try { -// gitRepositoryService.initRepository(tenantId, settings); -// } catch (Exception e) { -// log.warn("Failed to init repository for tenant {}", tenantId, e); -// } -// } -// }); -// } -// -// @Override -// public void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { -// var lock = getRepoLock(tenantId); -// lock.lock(); -// try { -// gitRepositoryService.testRepository(tenantId, settings); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } finally { -// lock.unlock(); -// } -// } -// -// @Override -// public void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) { -// var lock = getRepoLock(tenantId); -// lock.lock(); -// try { -// gitRepositoryService.initRepository(tenantId, settings); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } finally { -// lock.unlock(); -// } -// } -// -// @Override -// public void clearRepository(TenantId tenantId) { -// var lock = getRepoLock(tenantId); -// lock.lock(); -// try { -// gitRepositoryService.clearRepository(tenantId); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } finally { -// lock.unlock(); -// } -// } -// -// @Override -// public PendingCommit prepareCommit(TenantId tenantId, VersionCreateRequest request) { -// var lock = getRepoLock(tenantId); -// lock.lock(); -// try { -// var pendingCommit = new PendingCommit(tenantId, request); -// PendingCommit old = pendingCommitMap.put(tenantId, pendingCommit); -// if (old != null) { -// gitRepositoryService.abort(old); -// } -// gitRepositoryService.prepareCommit(pendingCommit); -// return pendingCommit; -// } finally { -// lock.unlock(); -// } -// } -// -// @Override -// public void deleteAll(PendingCommit commit, EntityType entityType) { -// doInsideLock(commit, c -> { -// try { -// gitRepositoryService.deleteFolderContent(commit, getRelativePath(entityType, null)); -// } catch (IOException e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } -// }); -// } -// -// @Override -// public void addToCommit(PendingCommit commit, EntityExportData> entityData) { -// doInsideLock(commit, c -> { -// String entityDataJson; -// try { -// entityDataJson = jsonWriter.writeValueAsString(entityData); -// gitRepositoryService.add(c, getRelativePath(entityData.getEntityType(), -// entityData.getEntity().getId().toString()), entityDataJson); -// } catch (IOException e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } -// }); -// } -// -// @Override -// public VersionCreationResult push(PendingCommit commit) { -// return executeInsideLock(commit, gitRepositoryService::push); -// } -// -// @Override -// public List listVersions(TenantId tenantId, String branch) { -// return listVersions(tenantId, branch, (String) null); -// } -// -// @Override -// public List listVersions(TenantId tenantId, String branch, EntityType entityType) { -// return listVersions(tenantId, branch, getRelativePath(entityType, null)); -// } -// -// @Override -// public List listVersions(TenantId tenantId, String branch, EntityId entityId) { -// return listVersions(tenantId, branch, getRelativePath(entityId.getEntityType(), entityId.getId().toString())); -// } -// -// @Override -// public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) { -// try { -// return gitRepositoryService.listEntitiesAtVersion(tenantId, branch, versionId, entityType != null ? getRelativePath(entityType, null) : null); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } -// } -// -// @Override -// public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) { -// return listEntitiesAtVersion(tenantId, branch, versionId, null); -// } -// -// @Override -// public List listBranches(TenantId tenantId) { -// return gitRepositoryService.listBranches(tenantId); -// } -// -// @Override -// public List> getEntities(TenantId tenantId, String branch, String versionId, EntityType entityType, int offset, int limit) { -// return listEntitiesAtVersion(tenantId, branch, versionId, entityType).stream() -// .skip(offset).limit(limit) -// .map(entityInfo -> getEntity(tenantId, versionId, entityInfo.getExternalId())) -// .collect(Collectors.toList()); -// } -// -// @Override -// public EntityExportData getEntity(TenantId tenantId, String versionId, EntityId entityId) { -// try { -// String entityDataJson = gitRepositoryService.getFileContentAtCommit(tenantId, -// getRelativePath(entityId.getEntityType(), entityId.getId().toString()), versionId); -// return JacksonUtil.fromString(entityDataJson, EntityExportData.class); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } -// } -// -// private EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId) { -// AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, EntitiesVersionControlService.SETTINGS_KEY); -// if (adminSettings != null) { -// try { -// return JacksonUtil.convertValue(adminSettings.getJsonValue(), EntitiesVersionControlSettings.class); -// } catch (Exception e) { -// throw new RuntimeException("Failed to load version control settings!", e); -// } -// } -// return null; -// } -// -// private List listVersions(TenantId tenantId, String branch, String path) { -// try { -// return gitRepositoryService.listVersions(tenantId, branch, path); -// } catch (Exception e) { -// //TODO: analyze and return meaningful exceptions that we can show to the client; -// throw new RuntimeException(e); -// } -// } -// -// private void doInsideLock(PendingCommit commit, Consumer r) { -// var lock = getRepoLock(commit.getTenantId()); -// lock.lock(); -// try { -// checkCommit(commit); -// r.accept(commit); -// } finally { -// lock.unlock(); -// } -// } -// -// private T executeInsideLock(PendingCommit commit, Function c) { -// var lock = getRepoLock(commit.getTenantId()); -// lock.lock(); -// try { -// checkCommit(commit); -// return c.apply(commit); -// } finally { -// lock.unlock(); -// } -// } -// -// private void checkCommit(PendingCommit commit) { -// PendingCommit existing = pendingCommitMap.get(commit.getTenantId()); -// if (existing == null || !existing.getRequestId().equals(commit.getRequestId())) { -// throw new ConcurrentModificationException(); -// } -// } -// -// private String getRelativePath(EntityType entityType, String entityId) { -// String path = entityType.name().toLowerCase(); -// if (entityId != null) { -// path += "/" + entityId + ".json"; -// } -// return path; -// } -// -// private Lock getRepoLock(TenantId tenantId) { -// return tenantRepoLocks.computeIfAbsent(tenantId, t -> new ReentrantLock()); -// } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java index 9b612cee5b..e63ba04f45 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java @@ -24,17 +24,19 @@ import java.util.UUID; @Getter public class PendingGitRequest { + private final long createdTime; private final UUID requestId; private final TenantId tenantId; private final SettableFuture future; public PendingGitRequest(TenantId tenantId) { + this.createdTime = System.currentTimeMillis(); this.requestId = UUID.randomUUID(); this.tenantId = tenantId; this.future = SettableFuture.create(); } - public boolean requiresSettings(){ + public boolean requiresSettings() { return true; } } diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 6d45698451..54e46eebcc 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -723,15 +723,39 @@ message ListVersionsRequestMsg { int64 entityIdLSB = 4; } +message EntityVersionProto { + int64 ts = 1; + string id = 2; + string name = 3; +} + +message ListVersionsResponseMsg { + repeated EntityVersionProto versions = 1; +} + message ListEntitiesRequestMsg { string branchName = 1; string versionId = 2; string entityType = 3; } +message VersionedEntityInfoProto { + string entityType = 1; + int64 entityIdMSB = 2; + int64 entityIdLSB = 3; +} + +message ListEntitiesResponseMsg { + repeated VersionedEntityInfoProto entities = 1; +} + message ListBranchesRequestMsg { } +message ListBranchesResponseMsg { + repeated string branches = 1; +} + message EntityContentRequestMsg { string versionId = 1; string entityType = 2; @@ -739,6 +763,10 @@ message EntityContentRequestMsg { int64 entityIdLSB = 4; } +message EntityContentResponseMsg { + string data = 1; +} + message EntitiesContentRequestMsg { string versionId = 1; string entityType = 2; @@ -746,6 +774,10 @@ message EntitiesContentRequestMsg { int32 limit = 4; } +message EntitiesContentResponseMsg { + repeated string data = 1; +} + message GenericRepositoryRequestMsg {} message GenericRepositoryResponseMsg {} @@ -774,6 +806,11 @@ message VersionControlResponseMsg { string error = 3; GenericRepositoryResponseMsg genericResponse = 4; CommitResponseMsg commitResponse = 5; + ListBranchesResponseMsg listBranchesResponse = 6; + ListEntitiesResponseMsg listEntitiesResponse = 7; + ListVersionsResponseMsg listVersionsResponse = 8; + EntityContentResponseMsg entityContentResponse = 9; + EntitiesContentResponseMsg entitiesContentResponse = 10; } /** diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java index 163fe4c6d2..fd278cde1f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java @@ -16,10 +16,16 @@ package org.thingsboard.server.common.data.sync.vc; import lombok.Data; +import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.id.EntityId; @Data +@NoArgsConstructor public class VersionedEntityInfo { private EntityId externalId; // etc.. + + public VersionedEntityInfo(EntityId externalId) { + this.externalId = externalId; + } } diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java index b9c595beac..b282799e24 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java @@ -23,9 +23,12 @@ import org.springframework.context.event.EventListener; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings; import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; +import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; @@ -58,6 +61,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; +import java.util.stream.Collectors; @Slf4j @TbVersionControlComponent @@ -144,9 +148,21 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe var newSettings = ctx.getSettings(); if (!newSettings.equals(currentSettings)) { vcService.initRepository(ctx.getTenantId(), ctx.getSettings()); + } else { + vcService.fetch(ctx.getTenantId()); } if (msg.hasCommitRequest()) { handleCommitRequest(ctx, msg.getCommitRequest()); + } else if (msg.hasListBranchesRequest()) { + handleListBranches(ctx, msg.getListBranchesRequest()); + } else if (msg.hasListEntitiesRequest()) { + handleListEntities(ctx, msg.getListEntitiesRequest()); + } else if (msg.hasListVersionRequest()) { + handleListVersions(ctx, msg.getListVersionRequest()); + } else if (msg.hasEntityContentRequest()) { + handleEntityContentRequest(ctx, msg.getEntityContentRequest()); + } else if (msg.hasEntitiesContentRequest()) { + handleEntitiesContentRequest(ctx, msg.getEntitiesContentRequest()); } } } @@ -172,12 +188,71 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe log.info("TB Version Control request consumer stopped."); } - private void handleCommitRequest(VersionControlRequestCtx ctx, CommitRequestMsg commitRequest) throws Exception { + private void handleEntitiesContentRequest(VersionControlRequestCtx ctx, EntitiesContentRequestMsg request) throws Exception { + var entityType = EntityType.valueOf(request.getEntityType()); + String path = getRelativePath(entityType, null); + var ids = vcService.listEntitiesAtVersion(ctx.getTenantId(), request.getVersionId(), path) + .stream().skip(request.getOffset()).limit(request.getLimit()).collect(Collectors.toList()); + var response = EntitiesContentResponseMsg.newBuilder(); + for (VersionedEntityInfo info : ids) { + var data = vcService.getFileContentAtCommit(ctx.getTenantId(), + getRelativePath(info.getExternalId().getEntityType(), info.getExternalId().getId().toString()), request.getVersionId()); + response.addData(data); + } + reply(ctx, Optional.empty(), builder -> builder.setEntitiesContentResponse(response)); + } + + private void handleEntityContentRequest(VersionControlRequestCtx ctx, EntityContentRequestMsg request) throws IOException { + String path = getRelativePath(EntityType.valueOf(request.getEntityType()), new UUID(request.getEntityIdMSB(), request.getEntityIdLSB()).toString()); + String data = vcService.getFileContentAtCommit(ctx.getTenantId(), path, request.getVersionId()); + reply(ctx, Optional.empty(), builder -> builder.setEntityContentResponse(EntityContentResponseMsg.newBuilder().setData(data))); + } + + private void handleListVersions(VersionControlRequestCtx ctx, ListVersionsRequestMsg request) throws Exception { + String path; + if (StringUtils.isNotEmpty(request.getEntityType())) { + var entityType = EntityType.valueOf(request.getEntityType()); + if (request.getEntityIdLSB() != 0 || request.getEntityIdMSB() != 0) { + path = getRelativePath(entityType, new UUID(request.getEntityIdMSB(), request.getEntityIdLSB()).toString()); + } else { + path = getRelativePath(entityType, null); + } + } else { + path = null; + } + var data = vcService.listVersions(ctx.getTenantId(), request.getBranchName(), path); + reply(ctx, Optional.empty(), builder -> + builder.setListVersionsResponse(ListVersionsResponseMsg.newBuilder() + .addAllVersions(data.stream().map( + v -> EntityVersionProto.newBuilder().setId(v.getId()).setName(v.getName()).build() + ).collect(Collectors.toList())))); + } + + private void handleListEntities(VersionControlRequestCtx ctx, ListEntitiesRequestMsg request) throws Exception { + EntityType entityType = StringUtils.isNotEmpty(request.getEntityType()) ? EntityType.valueOf(request.getEntityType()) : null; + var path = entityType != null ? getRelativePath(entityType, null) : null; + var data = vcService.listEntitiesAtVersion(ctx.getTenantId(), request.getVersionId(), path); + reply(ctx, Optional.empty(), builder -> + builder.setListEntitiesResponse(ListEntitiesResponseMsg.newBuilder() + .addAllEntities(data.stream().map(VersionedEntityInfo::getExternalId).map( + id -> VersionedEntityInfoProto.newBuilder() + .setEntityType(id.getEntityType().name()) + .setEntityIdMSB(id.getId().getMostSignificantBits()) + .setEntityIdLSB(id.getId().getLeastSignificantBits()).build() + ).collect(Collectors.toList())))); + } + + private void handleListBranches(VersionControlRequestCtx ctx, ListBranchesRequestMsg request) { + var branches = vcService.listBranches(ctx.getTenantId()); + reply(ctx, Optional.empty(), builder -> builder.setListBranchesResponse(ListBranchesResponseMsg.newBuilder().addAllBranches(branches))); + } + + private void handleCommitRequest(VersionControlRequestCtx ctx, CommitRequestMsg request) throws Exception { var tenantId = ctx.getTenantId(); - UUID txId = UUID.fromString(commitRequest.getTxId()); - if (commitRequest.hasPrepareMsg()) { - prepareCommit(ctx, txId, commitRequest.getPrepareMsg()); - } else if (commitRequest.hasAbortMsg()) { + UUID txId = UUID.fromString(request.getTxId()); + if (request.hasPrepareMsg()) { + prepareCommit(ctx, txId, request.getPrepareMsg()); + } else if (request.hasAbortMsg()) { PendingCommit current = pendingCommitMap.get(tenantId); if (current != null && current.getTxId().equals(txId)) { doAbortCurrentCommit(tenantId, current); @@ -186,11 +261,11 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe PendingCommit current = pendingCommitMap.get(tenantId); if (current != null && current.getTxId().equals(txId)) { try { - if (commitRequest.hasAddMsg()) { - addToCommit(ctx, current, commitRequest.getAddMsg()); - } else if (commitRequest.hasDeleteMsg()) { - deleteFromCommit(ctx, current, commitRequest.getDeleteMsg()); - } else if (commitRequest.hasPushMsg()) { + if (request.hasAddMsg()) { + addToCommit(ctx, current, request.getAddMsg()); + } else if (request.hasDeleteMsg()) { + deleteFromCommit(ctx, current, request.getDeleteMsg()); + } else if (request.hasPushMsg()) { reply(ctx, vcService.push(current)); } } catch (Exception e) { @@ -198,7 +273,7 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe throw e; } } else { - log.debug("[{}] Ignore request due to stale commit: {}", txId, commitRequest); + log.debug("[{}] Ignore request due to stale commit: {}", txId, request); } } } @@ -290,7 +365,7 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe builder.setGenericResponse(TransportProtos.GenericRepositoryResponseMsg.newBuilder().build()); } ToCoreNotificationMsg msg = ToCoreNotificationMsg.newBuilder().setVcResponseMsg(builder).build(); - log.trace("PUSHING msg: {} to: {}", msg, tpi); + log.trace("[{}][{}] PUSHING reply: {} to: {}", ctx.getTenantId(), ctx.getRequestId(), msg, tpi); producer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null); } @@ -304,9 +379,15 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe } } + private String getRelativePath(EntityType entityType, String entityId) { + String path = entityType.name().toLowerCase(); + if (entityId != null) { + path += "/" + entityId + ".json"; + } + return path; + } + private Lock getRepoLock(TenantId tenantId) { return tenantRepoLocks.computeIfAbsent(tenantId, t -> new ReentrantLock(true)); } - - } diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java index 0d55783a31..758641f6eb 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java @@ -160,6 +160,11 @@ public class DefaultGitRepositoryService implements GitRepositoryService { //TODO: implement; } + @Override + public void fetch(TenantId tenantId) { + //Fetch latest changes on demand. + } + @Override public String getFileContentAtCommit(TenantId tenantId, String relativePath, String versionId) throws IOException { GitRepository repository = checkRepository(tenantId); @@ -197,9 +202,8 @@ public class DefaultGitRepositoryService implements GitRepositoryService { } @Override - public List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception { + public List listEntitiesAtVersion(TenantId tenantId, String versionId, String path) throws Exception { GitRepository repository = checkRepository(tenantId); - checkVersion(tenantId, branch, versionId); return repository.listFilesAtCommit(versionId, path).stream() .map(filePath -> { EntityId entityId = fromRelativePath(filePath); diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java index c748147856..54ab91582e 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java @@ -30,7 +30,7 @@ public interface GitRepositoryService { List listVersions(TenantId tenantId, String branch, String path) throws Exception; - List listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception; + List listEntitiesAtVersion(TenantId tenantId, String versionId, String path) throws Exception; void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception; @@ -51,4 +51,6 @@ public interface GitRepositoryService { List listBranches(TenantId tenantId); String getFileContentAtCommit(TenantId tenantId, String relativePath, String versionId) throws IOException; + + void fetch(TenantId tenantId); }