From 626d4cc537512d8bb8ca3942fface6a0e52d7d40 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Tue, 14 Jan 2025 09:32:16 +0200 Subject: [PATCH] Add getting tenant with details (#2195) Signed-off-by: Avgustin Marinov --- ...pMessageHandlerServiceIntegrationTest.java | 4 +- .../mgmt/rest/resource/MgmtTargetMapper.java | 2 +- .../rest/resource/MgmtTargetResource.java | 2 +- .../hawkbit/repository/TargetManagement.java | 40 ++++++++++++- .../jpa/management/JpaActionManagement.java | 6 +- .../management/JpaConfirmationManagement.java | 11 ++-- .../management/JpaDeploymentManagement.java | 5 +- .../jpa/management/JpaSystemManagement.java | 21 ++----- .../jpa/management/JpaTargetManagement.java | 8 ++- .../repository/jpa/model/JpaAction.java | 4 +- .../repository/jpa/model/JpaTarget.java | 25 ++++++-- .../jpa/repository/HawkbitBaseRepository.java | 21 +++++-- .../jpa/repository/TargetRepository.java | 10 +++- .../ConfirmationManagementTest.java | 35 ++++++----- .../management/DeploymentManagementTest.java | 58 ++++++++----------- .../management/TargetTagManagementTest.java | 4 +- .../test/util/AbstractIntegrationTest.java | 18 +++--- 17 files changed, 162 insertions(+), 112 deletions(-) diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java index 67c36e5ab6..2636cd9e5b 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageHandlerServiceIntegrationTest.java @@ -994,9 +994,9 @@ void verifyDownloadAndInstallDirectlySendOnAutoConfirmationEnabled() { registerAndAssertTargetWithExistingTenant(controllerId); - assertThat(targetManagement.getByControllerID(controllerId).map(Target::getAutoConfirmationStatus)).isEmpty(); + assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNull(); confirmationManagement.activateAutoConfirmation(controllerId, null, null); - assertThat(targetManagement.getByControllerID(controllerId).map(Target::getAutoConfirmationStatus)).isPresent(); + assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNotNull(); final DistributionSetAssignmentResult assignmentResult = prepareDistributionSetAndAssign(controllerId); final Long actionId = getFirstAssignedActionId(assignmentResult); diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java index 0a322a1a40..2adf3eaab3 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetMapper.java @@ -306,7 +306,7 @@ static List toResponse(final String targetId, final Collection toResponse(targetId, action)).collect(Collectors.toList()); + return actions.stream().map(action -> toResponse(targetId, action)).toList(); } static MgmtMetadata toResponseTargetMetadata(final TargetMetadata metadata) { diff --git a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java index 0c233ec14b..bee192c565 100644 --- a/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java +++ b/hawkbit-mgmt/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResource.java @@ -416,7 +416,7 @@ public ResponseEntity> createMetadata(final String targetId, @Override public ResponseEntity getAutoConfirmStatus(final String targetId) { - final Target findTarget = findTargetWithExceptionIfNotFound(targetId); + final Target findTarget = targetManagement.getWithAutoConfigurationStatus(targetId); final MgmtTargetAutoConfirm state = MgmtTargetMapper.getTargetAutoConfirmResponse(findTarget); return ResponseEntity.ok(state); } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 7a43a9428d..c42224f264 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -50,6 +50,11 @@ */ public interface TargetManagement { + String DETAILS_BASE = "base"; + String DETAILS_AUTO_CONFIRMATION_STATUS = "autoConfirmationStatus"; + String DETAILS_TAGS = "tags"; + String DETAILS_ACTIONS = "actions"; + /** * Counts number of targets with the given distribution set assigned. * @@ -221,8 +226,8 @@ public interface TargetManagement { * @throws EntityNotFoundException if distribution set with given ID does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) - Slice findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(@NotNull Pageable pageRequest, - long distributionSetId, @NotNull String rsqlParam); + Slice findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable( + @NotNull Pageable pageRequest, long distributionSetId, @NotNull String rsqlParam); /** * Counts all targets for all the given parameter {@link TargetFilterQuery} and @@ -361,6 +366,37 @@ Page findByAssignedDistributionSetAndRsql(@NotNull Pageable pageReq, lon @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Optional getByControllerID(@NotEmpty String controllerId); + + /** + * Gets a {@link Target} based a given controller id and includes the details specified by the details key. + * + * @param controllerId to look for. + * @param detailsKey the key of the details to include, e.g. {@link #DETAILS_AUTO_CONFIRMATION_STATUS} + * @return {@link Target} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + Target getWithDetails(@NotEmpty String controllerId, String detailsKey); + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + default Target getWithDetails(@NotEmpty String controllerId) { + return getWithDetails(controllerId, DETAILS_BASE); + } + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + default Target getWithAutoConfigurationStatus(@NotEmpty String controllerId) { + return getWithDetails(controllerId, DETAILS_AUTO_CONFIRMATION_STATUS); + } + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + default Target getWithTags(@NotEmpty String controllerId) { + return getWithDetails(controllerId, DETAILS_TAGS); + } + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) + default Target getWithActions(@NotEmpty String controllerId) { + return getWithDetails(controllerId, DETAILS_ACTIONS); + } + /** * Filter {@link Target}s for all the given parameters. If all parameters except * pageable are null, all available {@link Target}s are returned. diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaActionManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaActionManagement.java index fadfd7f773..8a4537332b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaActionManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaActionManagement.java @@ -77,14 +77,14 @@ protected Action addActionStatus(final JpaActionStatusCreate statusCreate) { return handleAddUpdateActionStatus(actionStatus, action); } - log.debug("Update of actionStatus {} for action {} not possible since action not active anymore.", + log.debug( + "Update of actionStatus {} for action {} not possible since action not active anymore.", actionStatus.getStatus(), action.getId()); return action; } protected JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) { - return actionRepository.findById(actionId) - .orElseThrow(() -> new EntityNotFoundException(Action.class, actionId)); + return actionRepository.findById(actionId).orElseThrow(() -> new EntityNotFoundException(Action.class, actionId)); } protected void onActionStatusUpdate(final JpaActionStatus newActionStatus, final JpaAction action) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java index cda5a1d9b3..6f90b70648 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaConfirmationManagement.java @@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; import org.eclipse.hawkbit.repository.jpa.model.JpaAutoConfirmationStatus; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; @@ -84,7 +85,7 @@ public List findActiveActionsWaitingConfirmation(final String controller public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator, final String remark) { log.trace( "'activateAutoConfirmation' was called with values: controllerId={}; initiator={}; remark={}", controllerId, initiator, remark); - final JpaTarget target = targetRepository.getByControllerId(controllerId); + final JpaTarget target = targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS); if (target.getAutoConfirmationStatus() != null) { log.debug("'activateAutoConfirmation' was called for an controller id {} with active auto confirmation.", controllerId); throw new AutoConfirmationAlreadyActiveException(controllerId); @@ -109,18 +110,20 @@ public AutoConfirmationStatus activateAutoConfirmation(final String controllerId @Override public Optional getStatus(final String controllerId) { - return Optional.of(targetRepository.getByControllerId(controllerId)).map(JpaTarget::getAutoConfirmationStatus); + return Optional.of(targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS)) + .map(JpaTarget::getAutoConfirmationStatus); } @Override @Transactional public List autoConfirmActiveActions(final String controllerId) { - final JpaTarget target = targetRepository.getByControllerId(controllerId); + final JpaTarget target = targetRepository.getWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_AUTO_CONFIRMATION_STATUS); if (target.getAutoConfirmationStatus() == null) { // auto-confirmation is not active return Collections.emptyList(); + } else { + return giveConfirmationForActiveActions(target.getAutoConfirmationStatus()); } - return giveConfirmationForActiveActions(target.getAutoConfirmationStatus()); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java index 9f16d23ad1..94831ee246 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDeploymentManagement.java @@ -62,6 +62,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; @@ -494,12 +495,12 @@ public void startScheduledActions(final List rolloutGroupActions) { @Override public Optional getAssignedDistributionSet(final String controllerId) { - return targetRepository.findByControllerId(controllerId).map(JpaTarget::getAssignedDistributionSet); + return targetRepository.findWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_ASSIGNED_DISTRIBUTION_SET).map(JpaTarget::getAssignedDistributionSet); } @Override public Optional getInstalledDistributionSet(final String controllerId) { - return targetRepository.findByControllerId(controllerId).map(JpaTarget::getInstalledDistributionSet); + return targetRepository.findWithDetailsByControllerId(controllerId, JpaTarget_.GRAPH_TARGET_INSTALLED_DISTRIBUTION_SET).map(JpaTarget::getInstalledDistributionSet); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java index 0f97b30088..fd37d9610d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSystemManagement.java @@ -192,15 +192,12 @@ public void forEachTenant(final Consumer consumer) { return null; })); } while ((query = tenants.nextPageable()) != Pageable.unpaged()); - } @Override public SystemUsageReportWithTenants getSystemUsageStatisticsWithTenants() { final SystemUsageReportWithTenants result = (SystemUsageReportWithTenants) getSystemUsageStatistics(); - usageStatsPerTenant(result); - return result; } @@ -213,19 +210,11 @@ public SystemUsageReport getSystemUsageStatistics() { sumOfArtifacts = count.longValue(); } - // we use native queries to punch through the tenant boundaries. This - // has to be used with care! - final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target") - .getSingleResult()).longValue(); - - final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult()) - .longValue(); - - final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action") - .getSingleResult()).longValue(); - - return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts, - tenantMetaDataRepository.count()); + // we use native queries to punch through the tenant boundaries. This has to be used with care! + final long targets = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_target").getSingleResult()).longValue(); + final long artifacts = ((Number) entityManager.createNativeQuery(countArtifactQuery).getSingleResult()).longValue(); + final long actions = ((Number) entityManager.createNativeQuery("SELECT COUNT(id) FROM sp_action").getSingleResult()).longValue(); + return new SystemUsageReportWithTenants(targets, artifacts, actions, sumOfArtifacts, tenantMetaDataRepository.count()); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java index 3b4e7cef9d..b5b50d08d7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java @@ -409,6 +409,11 @@ public Optional getByControllerID(final String controllerId) { return targetRepository.findByControllerId(controllerId).map(Target.class::cast); } + @Override + public Target getWithDetails(final String controllerId, final String detailsKey) { + return targetRepository.getWithDetailsByControllerId(controllerId, "Target." + detailsKey); + } + @Override public Slice findByFilters(final Pageable pageable, final FilterParams filterParams) { final List> specList = buildSpecificationList(filterParams); @@ -719,8 +724,7 @@ public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(fi @Override public Set getTagsByControllerId(@NotEmpty String controllerId) { // the method has PreAuthorized by itself - return getByControllerID(controllerId).map(JpaTarget.class::cast).map(JpaTarget::getTags) - .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); + return ((JpaTarget)getWithTags(controllerId)).getTags(); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index cfb9f605dd..69b74c75b2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -65,13 +65,13 @@ @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) @NamedEntityGraphs({ - @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode(value = "target", subgraph = "target.ds"), @NamedAttributeNode("distributionSet") }, subgraphs = @NamedSubgraph( name = "target.ds", - attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) + attributeNodes = @NamedAttributeNode("assignedDistributionSet"))), + @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }) }) @Entity // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index e0e35c07c1..cd19db0147 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -34,6 +34,10 @@ import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToOne; import jakarta.persistence.MapKeyColumn; +import jakarta.persistence.NamedAttributeNode; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.NamedEntityGraphs; +import jakarta.persistence.NamedSubgraph; import jakarta.persistence.OneToMany; import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.Table; @@ -69,6 +73,7 @@ * JPA implementation of {@link Target}. */ @NoArgsConstructor // Default constructor for JPA +@Slf4j @Entity @Table(name = "sp_target", indexes = { @@ -78,9 +83,23 @@ @Index(name = "sp_idx_target_05", columnList = "tenant,last_modified_at"), @Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { "controller_id", "tenant" }, name = "uk_tenant_controller_id")) +@NamedEntityGraphs({ + @NamedEntityGraph(name = "Target.details", attributeNodes = { + @NamedAttributeNode("targetType"), + @NamedAttributeNode("installedDistributionSet"), + @NamedAttributeNode("assignedDistributionSet") }), + @NamedEntityGraph(name = "Target.targetType", attributeNodes = { @NamedAttributeNode("targetType") }), + @NamedEntityGraph(name = "Target.installedDistributionSet", attributeNodes = { @NamedAttributeNode("installedDistributionSet") }, + subgraphs = { @NamedSubgraph( + name = "installedDistributionSet.optLockRevision", + attributeNodes = @NamedAttributeNode("optLockRevision")) }), + @NamedEntityGraph(name = "Target.assignedDistributionSet", attributeNodes = { @NamedAttributeNode("assignedDistributionSet") }), + @NamedEntityGraph(name = "Target.autoConfirmationStatus", attributeNodes = { @NamedAttributeNode("autoConfirmationStatus") }), + @NamedEntityGraph(name = "Target.tags", attributeNodes = { @NamedAttributeNode("tags") }), + @NamedEntityGraph(name = "Target.actions", attributeNodes = { @NamedAttributeNode("actions") }), +}) // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities @SuppressWarnings("squid:S2160") -@Slf4j public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAwareEntity { @Serial @@ -281,10 +300,6 @@ public void addAction(final Action action) { actions.add((JpaAction) action); } - public List getActions() { - return actions == null ? Collections.emptyList() : Collections.unmodifiableList(actions); - } - @Override public void fireCreateEvent() { EventPublisherHolder.getInstance().getEventPublisher() diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/HawkbitBaseRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/HawkbitBaseRepository.java index f3762f89e2..d5fca818b6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/HawkbitBaseRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/HawkbitBaseRepository.java @@ -10,20 +10,19 @@ package org.eclipse.hawkbit.repository.jpa.repository; import java.io.Serializable; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import jakarta.persistence.EntityGraph; import jakarta.persistence.EntityManager; import jakarta.persistence.NoResultException; -import jakarta.persistence.Query; import jakarta.persistence.TypedQuery; import jakarta.transaction.Transactional; import org.eclipse.hawkbit.repository.BaseRepositoryTypeProvider; import org.eclipse.hawkbit.repository.jpa.acm.AccessController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -46,15 +45,18 @@ public class HawkbitBaseRepository extends SimpleJpa implements JpaSpecificationEntityGraphExecutor, NoCountSliceRepository, ACMRepository { private final EntityManager entityManager; + private final Logger log; public HawkbitBaseRepository(final Class domainClass, final EntityManager entityManager) { super(domainClass, entityManager); this.entityManager = entityManager; + log = LoggerFactory.getLogger(getDomainClass()); } public HawkbitBaseRepository(final JpaEntityInformation entityInformation, final EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; + log = LoggerFactory.getLogger(getDomainClass()); } @Override @@ -149,8 +151,17 @@ public String toString() { } private TypedQuery withEntityGraph(final TypedQuery query, final String entityGraph) { - final EntityGraph graph = ObjectUtils.isEmpty(entityGraph) ? null : entityManager.createEntityGraph(entityGraph); - return graph == null ? query : query.setHint("jakarta.persistence.loadgraph", graph); + if (ObjectUtils.isEmpty(entityGraph)) { + return query; + } else { + final EntityGraph graph = entityManager.createEntityGraph(entityGraph); + if (graph == null) { + log.warn("Entity graph {} not found", entityGraph); + return query; + } else { + return query.setHint("jakarta.persistence.loadgraph", graph); + } + } } private Page readPageWithoutCount(final TypedQuery query, final Pageable pageable) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetRepository.java index 009c143afa..11ff456454 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/repository/TargetRepository.java @@ -35,10 +35,14 @@ public interface TargetRepository extends BaseEntityRepository { default Optional findByControllerId(final String controllerId) { return findOne(TargetSpecifications.hasControllerId(controllerId)); } - + default Optional findWithDetailsByControllerId(final String controllerId, final String entityGraph) { + return findOne(TargetSpecifications.hasControllerId(controllerId), entityGraph); + } default JpaTarget getByControllerId(final String controllerId) { - return findOne(TargetSpecifications.hasControllerId(controllerId)) - .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); + return findByControllerId(controllerId).orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); + } + default JpaTarget getWithDetailsByControllerId(final String controllerId, final String entityGraph) { + return findWithDetailsByControllerId(controllerId, entityGraph).orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); } // TODO AC - remove it and use specification diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ConfirmationManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ConfirmationManagementTest.java index 988b3939de..b72a0298ec 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ConfirmationManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/ConfirmationManagementTest.java @@ -259,16 +259,15 @@ void verifyAutoConfirmationActivationValues(final String initiator, final String final String controllerId = testdataFactory.createTarget().getControllerId(); confirmationManagement.activateAutoConfirmation(controllerId, initiator, remark); - assertThat(targetManagement.getByControllerID(controllerId)).hasValueSatisfying(target -> { - assertThat(target.getAutoConfirmationStatus()).isNotNull() - .matches(status -> status.getTarget().getControllerId().equals(controllerId)) - .matches(status -> Objects.equals(status.getInitiator(), initiator)) - .matches(status -> Objects.equals(status.getCreatedBy(), "bumlux")) - .matches(status -> Objects.equals(status.getRemark(), remark)).satisfies(status -> { - final Instant activationTime = Instant.ofEpochMilli(status.getActivatedAt()); - assertThat(activationTime).isAfterOrEqualTo(activationTime.minusSeconds(3L)); - }); - }); + assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()) + .isNotNull() + .matches(status -> status.getTarget().getControllerId().equals(controllerId)) + .matches(status -> Objects.equals(status.getInitiator(), initiator)) + .matches(status -> Objects.equals(status.getCreatedBy(), "bumlux")) + .matches(status -> Objects.equals(status.getRemark(), remark)).satisfies(status -> { + final Instant activationTime = Instant.ofEpochMilli(status.getActivatedAt()); + assertThat(activationTime).isAfterOrEqualTo(activationTime.minusSeconds(3L)); + }); confirmationManagement.deactivateAutoConfirmation(controllerId); verifyAutoConfirmationIsDisabled(controllerId); @@ -280,8 +279,7 @@ void verifyActivateAlreadyActiveAutoConfirmationThrowException() { final String controllerId = testdataFactory.createTarget().getControllerId(); confirmationManagement.activateAutoConfirmation(controllerId, "any", "any"); - assertThat(targetManagement.getByControllerID(controllerId)) - .hasValueSatisfying(target -> assertThat(target.getAutoConfirmationStatus()).isNotNull()); + assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNotNull(); assertThatThrownBy(() -> confirmationManagement.activateAutoConfirmation(controllerId, "any", "any")) .isInstanceOf(AutoConfirmationAlreadyActiveException.class) @@ -299,8 +297,11 @@ void disableAlreadyDisabledAutoConfirmationHaveNoAffect() { } private static Stream getAutoConfirmationArguments() { - return Stream.of(Arguments.of("TestUser", "TestRemark"), Arguments.of("TestUser", null), - Arguments.of(null, "TestRemark"), Arguments.of(null, null)); + return Stream.of( + Arguments.of("TestUser", "TestRemark"), + Arguments.of("TestUser", null), + Arguments.of(null, "TestRemark"), + Arguments.of(null, null)); } private static DeploymentRequest toDeploymentRequest(final String controllerId, final Long distributionSetId) { @@ -308,8 +309,6 @@ private static DeploymentRequest toDeploymentRequest(final String controllerId, } private void verifyAutoConfirmationIsDisabled(final String controllerId) { - assertThat(targetManagement.getByControllerID(controllerId)) - .hasValueSatisfying(target -> assertThat(target.getAutoConfirmationStatus()).isNull()); + assertThat(targetManagement.getWithAutoConfigurationStatus(controllerId).getAutoConfirmationStatus()).isNull(); } - -} +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java index 8c7c85e3dc..e947c93763 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DeploymentManagementTest.java @@ -233,8 +233,7 @@ void findActionStatusByActionId() { final List testTarget = testdataFactory.createTargets(1); // one action with one action status is generated final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget)); - final Slice actions = deploymentManagement.findActionsByTarget(testTarget.get(0).getControllerId(), - PAGE); + final Slice actions = deploymentManagement.findActionsByTarget(testTarget.get(0).getControllerId(), PAGE); final ActionStatus expectedActionStatus = ((JpaAction) actions.getContent().get(0)).getActionStatus().get(0); // act @@ -374,7 +373,8 @@ void manualCancelWithMultipleAssignmentsCancelMiddleOneFirst() { final DistributionSet dsInstalled = action.getDistributionSet(); // check initial status - assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus()).as("wrong update status") + assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus()) + .as("wrong update status") .isEqualTo(TargetUpdateStatus.IN_SYNC); // assign the two sets in a row @@ -404,10 +404,12 @@ void manualCancelWithMultipleAssignmentsCancelMiddleOneFirst() { controllerManagement.addCancelActionStatus( entityFactory.actionStatus().create(secondAction.getId()).status(Status.CANCELED)); // cancelled success -> back to dsInstalled - assertThat(deploymentManagement.getAssignedDistributionSet("4712")).as("wrong installed ds") + assertThat(deploymentManagement.getAssignedDistributionSet("4712")) + .as("wrong installed ds") .contains(dsInstalled); assertThat(targetManagement.getByControllerID("4712").get().getUpdateStatus()) - .as("wrong target info update status").isEqualTo(TargetUpdateStatus.IN_SYNC); + .as("wrong target info update status") + .isEqualTo(TargetUpdateStatus.IN_SYNC); } @Test @@ -780,8 +782,7 @@ void assignmentWithAutoConfirmationWillBeHandledCorrectly(final boolean confirma confirmationManagement.activateAutoConfirmation(target.getControllerId(), "not_bumlux", "my personal remark"); - assertThat(targetManagement.getByControllerID(target.getControllerId())) - .hasValueSatisfying(t -> assertThat(t.getAutoConfirmationStatus()).isNotNull()); + assertThat(targetManagement.getWithAutoConfigurationStatus(target.getControllerId()).getAutoConfirmationStatus()).isNotNull(); final DistributionSet distributionSet = testdataFactory.createDistributionSet(); @@ -1038,26 +1039,21 @@ void assignDistributionSet2Targets() { final Iterable allFoundTargets = targetManagement.findAll(PAGE).getContent(); // get final updated version of targets - savedDeployedTargets = targetManagement.getByControllerID( - savedDeployedTargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())); + savedDeployedTargets = targetManagement.getByControllerID(savedDeployedTargets.stream().map(Target::getControllerId).toList()); assertThat(allFoundTargets).as("founded targets are wrong").containsAll(savedDeployedTargets) .containsAll(savedNakedTargets); - assertThat(savedDeployedTargets).as("saved target are wrong") - .doesNotContain(toArray(savedNakedTargets, Target.class)); - assertThat(savedNakedTargets).as("saved target are wrong") - .doesNotContain(toArray(savedDeployedTargets, Target.class)); + assertThat(savedDeployedTargets).as("saved target are wrong").doesNotContain(toArray(savedNakedTargets, Target.class)); + assertThat(savedNakedTargets).as("saved target are wrong").doesNotContain(toArray(savedDeployedTargets, Target.class)); for (final Target myt : savedNakedTargets) { final Target t = targetManagement.getByControllerID(myt.getControllerId()).get(); - assertThat(deploymentManagement.countActionsByTarget(t.getControllerId())).as("action should be empty") - .isZero(); + assertThat(deploymentManagement.countActionsByTarget(t.getControllerId())).as("action should be empty").isZero(); } for (final Target myt : savedDeployedTargets) { final Target t = targetManagement.getByControllerID(myt.getControllerId()).get(); - final List activeActionsByTarget = deploymentManagement - .findActiveActionsByTarget(PAGE, t.getControllerId()).getContent(); + final List activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(PAGE, t.getControllerId()).getContent(); assertThat(activeActionsByTarget).as("action should not be empty").isNotEmpty(); assertThat(t.getUpdateStatus()).as("wrong target update status").isEqualTo(TargetUpdateStatus.PENDING); for (final Action ua : activeActionsByTarget) { @@ -1373,7 +1369,7 @@ void alternatingAssignmentAndAddUpdateActionStatus() { assertThat(deploymentManagement.getAssignedDistributionSet(targ.getControllerId())) .as("Assigned distribution set of target is wrong").contains(dsA); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, targ.getControllerId()).getContent().get(0) - .getDistributionSet()).as("Distribution set of actionn is wrong").isEqualTo(dsA); + .getDistributionSet()).as("Distribution set of action is wrong").isEqualTo(dsA); assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, targ.getControllerId()).getContent().get(0) .getDistributionSet()).as("Installed distribution set of action should be null").isNotNull(); @@ -1554,31 +1550,25 @@ void verifyDSAssignmentForMultipleTargetsWithSameTargetType() { @Description("Verify that the DistributionSet assignments work for multiple targets of different target types.") void verifyDSAssignmentForMultipleTargetsWithDifferentTargetTypes() { final DistributionSet ds = testdataFactory.createDistributionSet("test-ds"); - final TargetType targetType1 = testdataFactory.createTargetType("test-type1", - Collections.singletonList(ds.getType())); - final TargetType targetType2 = testdataFactory.createTargetType("test-type2", - Collections.singletonList(ds.getType())); + final TargetType targetType1 = testdataFactory.createTargetType("test-type1", Collections.singletonList(ds.getType())); + final TargetType targetType2 = testdataFactory.createTargetType("test-type2", Collections.singletonList(ds.getType())); final Target target1 = testdataFactory.createTarget("test-target1", "test-target1", targetType1.getId()); final Target target2 = testdataFactory.createTarget("test-target2", "test-target2", targetType2.getId()); - final DeploymentRequest deployment1 = DeploymentManagement - .deploymentRequest(target1.getControllerId(), ds.getId()).build(); - final DeploymentRequest deployment2 = DeploymentManagement - .deploymentRequest(target2.getControllerId(), ds.getId()).build(); + final DeploymentRequest deployment1 = DeploymentManagement.deploymentRequest(target1.getControllerId(), ds.getId()).build(); + final DeploymentRequest deployment2 = DeploymentManagement.deploymentRequest(target2.getControllerId(), ds.getId()).build(); final List deploymentRequests = Arrays.asList(deployment1, deployment2); deploymentManagement.assignDistributionSets(deploymentRequests); implicitLock(ds); - final Optional assignedDsTarget1 = targetManagement - .getByControllerID(target1.getControllerId()).map(JpaTarget.class::cast) - .map(JpaTarget::getAssignedDistributionSet); - final Optional assignedDsTarget2 = targetManagement - .getByControllerID(target2.getControllerId()).map(JpaTarget.class::cast) - .map(JpaTarget::getAssignedDistributionSet); + final DistributionSet assignedDsTarget1 = ((JpaTarget)targetManagement + .getWithDetails(target1.getControllerId(), "assignedDistributionSet")).getAssignedDistributionSet(); + final DistributionSet assignedDsTarget2 = ((JpaTarget)targetManagement + .getWithDetails(target1.getControllerId(), "assignedDistributionSet")).getAssignedDistributionSet(); - assertThat(assignedDsTarget1).contains(ds); - assertThat(assignedDsTarget2).contains(ds); + assertThat(assignedDsTarget1).isEqualTo(ds); + assertThat(assignedDsTarget2).isEqualTo(ds); } @Test diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java index 9d3c3725dd..a97809ad82 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java @@ -176,14 +176,12 @@ void createTargetTag() { @Test @Description("Ensures that a deleted tag is removed from the repository as defined.") void deleteTargetTags() { - // create test data final Iterable tags = createTargetsWithTags(); final TargetTag toDelete = tags.iterator().next(); for (final Target target : targetRepository.findAll()) { - assertThat(getTargetTags(target.getControllerId())) - .contains(toDelete); + assertThat(getTargetTags(target.getControllerId())).contains(toDelete); } // delete diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java index f7a9d3a0e8..f42eb01593 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java @@ -51,6 +51,7 @@ import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTypeManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.DeploymentRequest; @@ -430,24 +431,23 @@ protected Action prepareFinishedUpdate() { return prepareFinishedUpdate(TestdataFactory.DEFAULT_CONTROLLER_ID, "", false); } - protected Action prepareFinishedUpdate(final String controllerId, final String distributionSet, - final boolean isRequiredMigrationStep) { + protected Action prepareFinishedUpdate(final String controllerId, final String distributionSet, final boolean isRequiredMigrationStep) { final DistributionSet ds = testdataFactory.createDistributionSet(distributionSet, isRequiredMigrationStep); Target savedTarget = testdataFactory.createTarget(controllerId); - savedTarget = getFirstAssignedTarget( - assignDistributionSet(ds.getId(), savedTarget.getControllerId(), ActionType.FORCED)); - Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()) - .getContent().get(0); + savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId(), ActionType.FORCED)); + final Action savedAction = deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId()).getContent().get(0); if (savedAction.getStatus() == Action.Status.WAIT_FOR_CONFIRMATION) { confirmationManagement.confirmAction(savedAction.getId(), null, null); } - savedAction = controllerManagement.addUpdateActionStatus( + controllerManagement.addUpdateActionStatus( entityFactory.actionStatus().create(savedAction.getId()).status(Action.Status.RUNNING)); - - return controllerManagement.addUpdateActionStatus( + controllerManagement.addUpdateActionStatus( entityFactory.actionStatus().create(savedAction.getId()).status(Action.Status.FINISHED)); + + return controllerManagement.findActionWithDetails(savedAction.getId()) + .orElseThrow(() -> new EntityNotFoundException(Action.class, savedAction.getId())); } protected void enableBatchAssignments() {