From 43176d37fc8cc5e97b2d8187d8a013465a9019c1 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 23 May 2025 15:20:08 +0300 Subject: [PATCH] Add entity name for jobs --- .../server/service/job/DefaultJobManager.java | 7 ++-- .../server/service/job/JobManagerTest.java | 2 ++ .../server/dao/entity/EntityService.java | 5 +++ .../server/common/data/job/Job.java | 1 + .../server/dao/entity/BaseEntityService.java | 32 ++++++++++++++++++- .../server/dao/sql/job/JpaJobDao.java | 20 +++++++++++- .../rule/engine/api/JobManager.java | 5 ++- 7 files changed, 64 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/job/DefaultJobManager.java b/application/src/main/java/org/thingsboard/server/service/job/DefaultJobManager.java index 2ed8ed8a42..ed8e613f38 100644 --- a/application/src/main/java/org/thingsboard/server/service/job/DefaultJobManager.java +++ b/application/src/main/java/org/thingsboard/server/service/job/DefaultJobManager.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.service.job; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; @@ -49,7 +51,6 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; import java.util.function.Function; import java.util.stream.Collectors; @@ -78,9 +79,9 @@ public class DefaultJobManager implements JobManager { } @Override - public Future submitJob(Job job) { + public ListenableFuture submitJob(Job job) { log.debug("Submitting job: {}", job); - return executor.submit(() -> jobService.saveJob(job.getTenantId(), job)); + return Futures.submit(() -> jobService.saveJob(job.getTenantId(), job), executor); } @Override diff --git a/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java b/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java index 0243d119b1..0278e910d9 100644 --- a/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java +++ b/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java @@ -248,6 +248,8 @@ public class JobManagerTest extends AbstractControllerTest { assertThat(job.getStatus()).isEqualTo(JobStatus.COMPLETED); assertThat(job.getResult().getSuccessfulCount()).isEqualTo(tasksCount); assertThat(job.getResult().getTotalCount()).isEqualTo(tasksCount); + assertThat(job.getEntityId()).isEqualTo(jobEntity.getId()); + assertThat(job.getEntityName()).isEqualTo(jobEntity.getName()); } }); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index 65db0d5a76..9adf703e0b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.entity; +import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; @@ -25,7 +26,9 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; +import java.util.Map; import java.util.Optional; +import java.util.Set; public interface EntityService { @@ -37,6 +40,8 @@ public interface EntityService { Optional> fetchEntity(TenantId tenantId, EntityId entityId); + Map fetchEntityInfos(TenantId tenantId, CustomerId customerId, Set entityIds); + Optional fetchNameLabelAndCustomerDetails(TenantId tenantId, EntityId entityId); long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/job/Job.java b/common/data/src/main/java/org/thingsboard/server/common/data/job/Job.java index 3cfb55b388..4af60bbd5e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/job/Job.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/job/Job.java @@ -47,6 +47,7 @@ public class Job extends BaseData implements HasTenantId { private String key; @NotNull private EntityId entityId; + private String entityName; // read-only @NotNull private JobStatus status; @NotNull diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index be7cbf7f84..d7e313e7fd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasEmail; @@ -41,19 +42,24 @@ import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.EntityKey; +import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityListFilter; import org.thingsboard.server.common.data.query.EntityNameFilter; import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.data.query.RelationsQueryFilter; +import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.common.msg.edqs.EdqsApiService; import org.thingsboard.server.common.stats.EdqsStatsService; import org.thingsboard.server.dao.exception.IncorrectParameterException; +import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -199,6 +205,30 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return fetchAndConvert(tenantId, entityId, Function.identity()); } + @Override + public Map fetchEntityInfos(TenantId tenantId, CustomerId customerId, Set entityIds) { + Map infos = new HashMap<>(); + entityIds.stream() + .collect(Collectors.groupingBy(EntityId::getEntityType)) + .forEach((entityType, ids) -> { + EntityListFilter filter = new EntityListFilter(); + filter.setEntityType(entityType); + filter.setEntityList(ids.stream().map(Object::toString).toList()); + EntityDataQuery query = new EntityDataQuery(filter, new EntityDataPageLink(ids.size(), 0, null, null), + List.of(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.NAME_PROPERTY)), Collections.emptyList(), Collections.emptyList()); + + entityQueryDao.findEntityDataByQuery(tenantId, customerId, query).getData().forEach(entityData -> { + EntityId entityId = entityData.getEntityId(); + Optional.ofNullable(entityData.getLatest().get(EntityKeyType.ENTITY_FIELD)) + .map(fields -> fields.get(ModelConstants.NAME_PROPERTY)) + .map(TsValue::getValue).ifPresent(name -> { + infos.put(entityId, new EntityInfo(entityId, name)); + }); + }); + }); + return infos; + } + private Optional fetchAndConvert(TenantId tenantId, EntityId entityId, Function, T> converter) { EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); Optional> entityOpt = entityDaoService.findEntity(tenantId, entityId); @@ -295,7 +325,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe } if ((query.getEntityFields() == null || query.getEntityFields().isEmpty()) && - (query.getLatestValues() == null || query.getLatestValues().isEmpty())) { + (query.getLatestValues() == null || query.getLatestValues().isEmpty())) { return false; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/job/JpaJobDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/job/JpaJobDao.java index 40d5177ad6..339f6af033 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/job/JpaJobDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/job/JpaJobDao.java @@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Limit; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.JobId; @@ -32,13 +33,17 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.job.JobDao; import org.thingsboard.server.dao.model.sql.JobEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.util.SqlDao; import java.util.Arrays; +import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; @Component @SqlDao @@ -46,16 +51,29 @@ import java.util.UUID; public class JpaJobDao extends JpaAbstractDao implements JobDao { private final JobRepository jobRepository; + private final EntityService entityService; @Override public PageData findByTenantIdAndFilter(TenantId tenantId, JobFilter filter, PageLink pageLink) { - return DaoUtil.toPageData(jobRepository.findByTenantIdAndTypesAndStatusesAndEntitiesAndTimeAndSearchText(tenantId.getId(), + PageData jobs = DaoUtil.toPageData(jobRepository.findByTenantIdAndTypesAndStatusesAndEntitiesAndTimeAndSearchText(tenantId.getId(), CollectionsUtil.isEmpty(filter.getTypes()) ? null : filter.getTypes(), CollectionsUtil.isEmpty(filter.getStatuses()) ? null : filter.getStatuses(), CollectionsUtil.isEmpty(filter.getEntities()) ? null : filter.getEntities(), filter.getStartTime() != null ? filter.getStartTime() : 0, filter.getEndTime() != null ? filter.getEndTime() : 0, Strings.emptyToNull(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink))); + + Set entityIds = jobs.getData().stream() + .map(Job::getEntityId) + .collect(Collectors.toSet()); + Map entityInfos = entityService.fetchEntityInfos(tenantId, null, entityIds); + jobs.getData().forEach(job -> { + EntityInfo entityInfo = entityInfos.get(job.getEntityId()); + if (entityInfo != null) { + job.setEntityName(entityInfo.getName()); + } + }); + return jobs; } @Override diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/JobManager.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/JobManager.java index aa48f9a9fb..ed8931f88e 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/JobManager.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/JobManager.java @@ -15,15 +15,14 @@ */ package org.thingsboard.rule.engine.api; +import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.id.JobId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.job.Job; -import java.util.concurrent.Future; - public interface JobManager { - Future submitJob(Job job); // TODO: rate limits + ListenableFuture submitJob(Job job); // TODO: rate limits void cancelJob(TenantId tenantId, JobId jobId);