Cleanup TargetManagement (#2601)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -9,33 +9,14 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_DELAY;
|
||||
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTagSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@ConditionalOnBooleanProperty(prefix = "hawkbit.jpa", name = { "enabled", "distribution-set-tag-management" }, matchIfMissing = true)
|
||||
|
||||
@@ -211,7 +211,7 @@ class JpaTargetFilterQueryManagement
|
||||
|
||||
private void assertMaxTargetsQuota(final String query, final String filterName, final long dsId) {
|
||||
QuotaHelper.assertAssignmentQuota(filterName,
|
||||
targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(dsId, query),
|
||||
targetManagement.countByRsqlAndNonDsAndCompatibleAndUpdatable(dsId, query),
|
||||
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.JpaManagementHelper.combineWithAnd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -35,14 +34,9 @@ import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.metamodel.MapAttribute;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TimestampCalculator;
|
||||
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
@@ -52,9 +46,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
@@ -66,12 +58,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -82,7 +70,6 @@ import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
@@ -100,9 +87,7 @@ public class JpaTargetManagement
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final TargetTypeRepository targetTypeRepository;
|
||||
private final RolloutGroupRepository rolloutGroupRepository;
|
||||
private final TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
private final TargetTagRepository targetTagRepository;
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
@SuppressWarnings("java:S107")
|
||||
protected JpaTargetManagement(
|
||||
@@ -110,83 +95,41 @@ public class JpaTargetManagement
|
||||
final JpaDistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final TargetTypeRepository targetTypeRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTagRepository targetTagRepository,
|
||||
final TenantAware tenantAware) {
|
||||
final TargetTagRepository targetTagRepository) {
|
||||
super(jpaRepository, entityManager);
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.targetTypeRepository = targetTypeRepository;
|
||||
this.rolloutGroupRepository = rolloutGroupRepository;
|
||||
this.targetFilterQueryRepository = targetFilterQueryRepository;
|
||||
this.targetTagRepository = targetTagRepository;
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAssignedDistributionSet(final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
|
||||
return jpaRepository.count(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
|
||||
public Map<String, String> getControllerAttributes(final String controllerId) {
|
||||
return getMap(controllerId, JpaTarget_.controllerAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFilters(final FilterParams filterParams) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByInstalledDistributionSet(final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
|
||||
return jpaRepository.count(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsByInstalledOrAssignedDistributionSet(final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
|
||||
return jpaRepository.exists(TargetSpecifications.hasInstalledOrAssignedDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndUpdatable(String rsql) {
|
||||
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
|
||||
final String controllerId, final long distributionSetId, final String targetFilterQuery) {
|
||||
RsqlUtility.getInstance().validateRsqlFor(targetFilterQuery, TargetFields.class, JpaTarget.class);
|
||||
final DistributionSet ds = distributionSetManagement.get(distributionSetId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId));
|
||||
final Long distSetTypeId = ds.getType().getId();
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class));
|
||||
return jpaRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(targetFilterQuery, TargetFields.class),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
|
||||
TargetSpecifications.hasControllerId(controllerId));
|
||||
|
||||
final Specification<JpaTarget> combinedSpecification = Objects
|
||||
.requireNonNull(SpecificationsBuilder.combineWithAnd(specList));
|
||||
return jpaRepository.exists(AccessController.Operation.UPDATE, combinedSpecification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFailedInRollout(final String rolloutId, final Long dsTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(TargetSpecifications.failedActionsForRollout(rolloutId));
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByTargetFilterQuery(final long targetFilterQueryId) {
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryRepository
|
||||
.findById(targetFilterQueryId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
|
||||
return countByRsql(targetFilterQuery.getQuery());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void deleteByControllerID(final String controllerId) {
|
||||
jpaRepository.delete(getByControllerIdAndThrowIfNotFound(controllerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(final long distributionSetId, final String rsql,
|
||||
final Pageable pageable) {
|
||||
public Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(
|
||||
final long distributionSetId, final String rsql, final Pageable pageable) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
|
||||
@@ -202,16 +145,18 @@ public class JpaTargetManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndNonDSAndCompatibleAndUpdatable(final long distributionSetId, final String rsql) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
public List<Target> getByControllerId(final Collection<String> controllerIDs) {
|
||||
return Collections.unmodifiableList(jpaRepository.findAll(TargetSpecifications.byControllerIdWithAssignedDsInJoin(controllerIDs)));
|
||||
}
|
||||
|
||||
return jpaRepository.count(
|
||||
AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
|
||||
@Override
|
||||
public Optional<Target> getByControllerId(final String controllerId) {
|
||||
return jpaRepository.findByControllerId(controllerId).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target getWithDetails(final String controllerId, final String detailsKey) {
|
||||
return jpaRepository.getWithDetailsByControllerId(controllerId, "Target." + detailsKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,16 +172,6 @@ public class JpaTargetManagement
|
||||
.map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
final String rsql, final Collection<Long> groups, final DistributionSetType dsType) {
|
||||
return jpaRepository.count(AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByFailedRolloutAndNotInRolloutGroups(String rolloutId, Collection<Long> groups, Pageable pageable) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
@@ -245,14 +180,6 @@ public class JpaTargetManagement
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFailedRolloutAndNotInRolloutGroups(String rolloutId, Collection<Long> groups) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups));
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByRsqlAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable(
|
||||
final long rolloutId, final String rsql, final DistributionSetType distributionSetType, final Pageable pageable) {
|
||||
@@ -266,11 +193,6 @@ public class JpaTargetManagement
|
||||
.map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByActionsInRolloutGroup(final long rolloutGroupId) {
|
||||
return jpaRepository.count(TargetSpecifications.isInActionRolloutGroup(rolloutGroupId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByInRolloutGroupWithoutAction(final long group, final Pageable pageable) {
|
||||
if (!rolloutGroupRepository.existsById(group)) {
|
||||
@@ -301,27 +223,6 @@ public class JpaTargetManagement
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Target> getByControllerId(final Collection<String> controllerIDs) {
|
||||
return Collections.unmodifiableList(jpaRepository.findAll(TargetSpecifications.byControllerIdWithAssignedDsInJoin(controllerIDs)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Target> getByControllerId(final String controllerId) {
|
||||
return jpaRepository.findByControllerId(controllerId).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target getWithDetails(final String controllerId, final String detailsKey) {
|
||||
return jpaRepository.getWithDetailsByControllerId(controllerId, "Target." + detailsKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByFilters(final FilterParams filterParams, final Pageable pageable) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(jpaRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByInstalledDistributionSet(final long distributionSetId, final Pageable pageReq) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
@@ -341,23 +242,6 @@ public class JpaTargetManagement
|
||||
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByUpdateStatus(final TargetUpdateStatus status, final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(
|
||||
jpaRepository, List.of(TargetSpecifications.hasTargetUpdateStatus(status)), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQuery(final long targetFilterQueryId, final Pageable pageable) {
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryRepository.findById(targetFilterQueryId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(
|
||||
jpaRepository, List.of(RsqlUtility.getInstance().buildRsqlSpecification(
|
||||
targetFilterQuery.getQuery(), TargetFields.class)), pageable
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByTag(final long tagId, final Pageable pageable) {
|
||||
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
|
||||
@@ -376,44 +260,61 @@ public class JpaTargetManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetTypeAssignmentResult assignType(final Collection<String> controllerIds, final Long typeId) {
|
||||
final JpaTargetType type = targetTypeRepository
|
||||
.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, typeId));
|
||||
public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
final List<JpaTarget> targetsWithSameType = findTargetsByInSpecification(controllerIds, TargetSpecifications.hasTargetType(typeId));
|
||||
final List<JpaTarget> targetsWithoutSameType =
|
||||
findTargetsByInSpecification(controllerIds, TargetSpecifications.hasTargetTypeNot(typeId));
|
||||
@Override
|
||||
public long countByFailedInRollout(final String rolloutId, final Long dsTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(TargetSpecifications.failedActionsForRollout(rolloutId));
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
// set new target type to all targets without that type
|
||||
targetsWithoutSameType.forEach(target -> target.setTargetType(type));
|
||||
@Override
|
||||
public long countByRsqlAndNonDsAndCompatibleAndUpdatable(final long distributionSetId, final String rsql) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
|
||||
final TargetTypeAssignmentResult result = new TargetTypeAssignmentResult(
|
||||
targetsWithSameType.size(), jpaRepository.saveAll(targetsWithoutSameType), Collections.emptyList(), type);
|
||||
return jpaRepository.count(
|
||||
AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
|
||||
}
|
||||
|
||||
// no reason to persist the type
|
||||
entityManager.detach(type);
|
||||
return result;
|
||||
@Override
|
||||
public long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
final String rsql, final Collection<Long> groups, final DistributionSetType dsType) {
|
||||
return jpaRepository.count(AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFailedRolloutAndNotInRolloutGroups(String rolloutId, Collection<Long> groups) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups));
|
||||
return JpaManagementHelper.countBySpec(jpaRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByActionsInRolloutGroup(final long rolloutGroupId) {
|
||||
return jpaRepository.count(TargetSpecifications.isInActionRolloutGroup(rolloutGroupId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetTypeAssignmentResult unassignType(final Collection<String> controllerIds) {
|
||||
final List<JpaTarget> allTargets = findTargetsByInSpecification(controllerIds, null);
|
||||
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds, allTargets.stream().map(Target::getControllerId).toList());
|
||||
}
|
||||
|
||||
// set new target type to null for all targets
|
||||
allTargets.forEach(target -> target.setTargetType(null));
|
||||
|
||||
return new TargetTypeAssignmentResult(0, Collections.emptyList(), jpaRepository.saveAll(allTargets), null);
|
||||
public void deleteByControllerId(final String controllerId) {
|
||||
jpaRepository.delete(getByControllerIdAndThrowIfNotFound(controllerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -445,6 +346,12 @@ public class JpaTargetManagement
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TargetTag> getTags(@NotEmpty String controllerId) {
|
||||
// the method has PreAuthorized by itself
|
||||
return ((JpaTarget) getWithDetails(controllerId, DETAILS_TAGS)).getTags();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
@@ -474,16 +381,6 @@ public class JpaTargetManagement
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target unassignType(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
target.setTargetType(null);
|
||||
return jpaRepository.save(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
@@ -500,23 +397,15 @@ public class JpaTargetManagement
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findTargetsByGroup(String group, final boolean withSubgroups, final Pageable pageable) {
|
||||
if (withSubgroups) {
|
||||
// search for eq(group) and like(group%)
|
||||
return JpaManagementHelper
|
||||
.findAllWithCountBySpec(jpaRepository, List.of(TargetSpecifications.eqOrSubTargetGroup(group)), pageable);
|
||||
} else {
|
||||
return JpaManagementHelper
|
||||
.findAllWithCountBySpec(jpaRepository, List.of(TargetSpecifications.eqTargetGroup(group)), pageable);
|
||||
}
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target unassignType(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
target.setTargetType(null);
|
||||
return jpaRepository.save(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findGroups() {
|
||||
return jpaRepository.findDistinctGroups();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
@@ -547,69 +436,23 @@ public class JpaTargetManagement
|
||||
controllerIds.forEach(in::value);
|
||||
|
||||
entityManager.createQuery(criteriaQuery.set("group", group).where(in)).executeUpdate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsByControllerId(final String controllerId) {
|
||||
return jpaRepository.exists(TargetSpecifications.hasControllerId(controllerId));
|
||||
public Page<Target> findTargetsByGroup(String group, final boolean withSubgroups, final Pageable pageable) {
|
||||
if (withSubgroups) {
|
||||
// search for eq(group) and like(group%)
|
||||
return JpaManagementHelper
|
||||
.findAllWithCountBySpec(jpaRepository, List.of(TargetSpecifications.eqOrSubTargetGroup(group)), pageable);
|
||||
} else {
|
||||
return JpaManagementHelper
|
||||
.findAllWithCountBySpec(jpaRepository, List.of(TargetSpecifications.eqTargetGroup(group)), pageable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
|
||||
final String controllerId, final long distributionSetId, final String targetFilterQuery) {
|
||||
RsqlUtility.getInstance().validateRsqlFor(targetFilterQuery, TargetFields.class, JpaTarget.class);
|
||||
final DistributionSet ds = distributionSetManagement.get(distributionSetId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId));
|
||||
final Long distSetTypeId = ds.getType().getId();
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RsqlUtility.getInstance().buildRsqlSpecification(targetFilterQuery, TargetFields.class),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
|
||||
TargetSpecifications.hasControllerId(controllerId));
|
||||
|
||||
final Specification<JpaTarget> combinedSpecification = Objects
|
||||
.requireNonNull(SpecificationsBuilder.combineWithAnd(specList));
|
||||
return jpaRepository.exists(AccessController.Operation.UPDATE, combinedSpecification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TargetTag> getTags(@NotEmpty String controllerId) {
|
||||
// the method has PreAuthorized by itself
|
||||
return ((JpaTarget) getWithTags(controllerId)).getTags();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getControllerAttributes(final String controllerId) {
|
||||
return getMap(controllerId, JpaTarget_.controllerAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void requestControllerAttributes(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
jpaRepository.getAccessController()
|
||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
||||
target.setRequestControllerAttributes(true);
|
||||
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() ->
|
||||
EventPublisherHolder.getInstance().getEventPublisher()
|
||||
.publishEvent(new TargetAttributesRequestedEvent(
|
||||
tenantAware.getCurrentTenant(), target.getId(), JpaTarget.class, target.getControllerId(),
|
||||
target.getAddress() != null ? target.getAddress().toString() : null
|
||||
)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControllerAttributesRequested(final String controllerId) {
|
||||
return getByControllerIdAndThrowIfNotFound(controllerId).isRequestControllerAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByControllerAttributesRequested(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(
|
||||
jpaRepository, List.of(TargetSpecifications.hasRequestControllerAttributesTrue()), pageable);
|
||||
public List<String> findGroups() {
|
||||
return jpaRepository.findDistinctGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -695,22 +538,6 @@ public class JpaTargetManagement
|
||||
.collect(Collectors.toMap(entry -> (String) entry[0], entry -> (String) entry[1], (v1, v2) -> v1, LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private static boolean hasTagsFilterActive(final FilterParams filterParams) {
|
||||
final boolean isNoTagActive = Boolean.TRUE.equals(filterParams.getSelectTargetWithNoTag());
|
||||
final boolean isAtLeastOneTagActive = filterParams.getFilterByTagNames() != null
|
||||
&& filterParams.getFilterByTagNames().length > 0;
|
||||
|
||||
return isNoTagActive || isAtLeastOneTagActive;
|
||||
}
|
||||
|
||||
private static boolean hasTypesFilterActive(final FilterParams filterParams) {
|
||||
return filterParams.getFilterByTargetType() != null;
|
||||
}
|
||||
|
||||
private static boolean hasNoTypeFilterActive(final FilterParams filterParams) {
|
||||
return Boolean.TRUE.equals(filterParams.getSelectTargetWithNoTargetType());
|
||||
}
|
||||
|
||||
private static Collection<String> notFound(final Collection<String> controllerIds, final List<JpaTarget> foundTargets) {
|
||||
final Map<String, JpaTarget> foundTargetMap = foundTargets.stream()
|
||||
.collect(Collectors.toMap(Target::getControllerId, Function.identity()));
|
||||
@@ -730,43 +557,6 @@ public class JpaTargetManagement
|
||||
QuotaHelper.assertAssignmentQuota(targetId, requested, limit, "Metadata", Target.class.getSimpleName(), null);
|
||||
}
|
||||
|
||||
private List<Specification<JpaTarget>> buildSpecificationList(final FilterParams filterParams) {
|
||||
final List<Specification<JpaTarget>> specList = new ArrayList<>();
|
||||
if ((filterParams.getFilterByStatus() != null) && !filterParams.getFilterByStatus().isEmpty()) {
|
||||
specList.add(TargetSpecifications.hasTargetUpdateStatus(filterParams.getFilterByStatus()));
|
||||
}
|
||||
if (filterParams.getOverdueState() != null && filterParams.getOverdueState()) {
|
||||
specList.add(TargetSpecifications.isOverdue(TimestampCalculator.calculateOverdueTimestamp()));
|
||||
}
|
||||
if (filterParams.getFilterByDistributionId() != null) {
|
||||
final DistributionSet validDistSet = distributionSetManagement
|
||||
.getOrElseThrowException(filterParams.getFilterByDistributionId());
|
||||
|
||||
specList.add(TargetSpecifications.hasInstalledOrAssignedDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(filterParams.getFilterBySearchText())) {
|
||||
specList.add(TargetSpecifications.likeControllerIdOrName(filterParams.getFilterBySearchText()));
|
||||
}
|
||||
if (hasTagsFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasTags(filterParams.getFilterByTagNames(),
|
||||
filterParams.getSelectTargetWithNoTag()));
|
||||
}
|
||||
|
||||
if (hasTypesFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasTargetType(filterParams.getFilterByTargetType()));
|
||||
} else if (hasNoTypeFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasNoTargetType());
|
||||
}
|
||||
|
||||
return specList;
|
||||
}
|
||||
|
||||
private List<JpaTarget> findTargetsByInSpecification(final Collection<String> controllerIds, final Specification<JpaTarget> specification) {
|
||||
return ListUtils.partition(new ArrayList<>(controllerIds), Constants.MAX_ENTRIES_IN_STATEMENT).stream()
|
||||
.map(ids -> jpaRepository.findAll(TargetSpecifications.hasControllerIdIn(ids).and(specification)))
|
||||
.flatMap(List::stream).toList();
|
||||
}
|
||||
|
||||
private List<Target> updateTag(
|
||||
final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler,
|
||||
final BiFunction<JpaTargetTag, JpaTarget, Target> updater) {
|
||||
@@ -776,8 +566,7 @@ public class JpaTargetManagement
|
||||
jpaRepository.findByControllerId(controllerIds.iterator().next())
|
||||
.map(List::of)
|
||||
.orElseGet(Collections::emptyList) :
|
||||
jpaRepository
|
||||
.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
jpaRepository.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
if (targets.size() < controllerIds.size()) {
|
||||
final Collection<String> notFound = notFound(controllerIds, targets);
|
||||
if (notFoundHandler == null) {
|
||||
|
||||
@@ -78,10 +78,6 @@ public final class ActionSpecifications {
|
||||
isNull ? cb.isNull(root.get(JpaAction_.weight)) : cb.isNotNull(root.get(JpaAction_.weight)));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byDistributionSetId(final Long distributionSetId) {
|
||||
return (root, query, cb) -> cb.equal(root.get(JpaAction_.distributionSet).get(AbstractJpaBaseEntity_.id), distributionSetId);
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byDistributionSetIdAndActive(final Long distributionSetId) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.distributionSet).get(AbstractJpaBaseEntity_.id), distributionSetId),
|
||||
|
||||
@@ -77,23 +77,6 @@ public final class DistributionSetSpecification {
|
||||
return (dsRoot, query, cb) -> cb.equal(dsRoot.get(JpaDistributionSet_.valid), isValid);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet} with given {@link DistributionSet#getId()}.
|
||||
*
|
||||
* @param distid to search
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> byIdFetch(final Long distid) {
|
||||
return (dsRoot, query, cb) -> {
|
||||
final Predicate predicate = cb.equal(dsRoot.get(AbstractJpaBaseEntity_.id), distid);
|
||||
dsRoot.fetch(JpaDistributionSet_.modules, JoinType.LEFT);
|
||||
dsRoot.fetch(JpaDistributionSet_.type, JoinType.LEFT);
|
||||
query.distinct(true);
|
||||
|
||||
return predicate;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet} with given {@link DistributionSet#getId()}s.
|
||||
*
|
||||
@@ -162,16 +145,6 @@ public final class DistributionSetSpecification {
|
||||
return (dsRoot, query, cb) -> cb.equal(dsRoot.get(JpaDistributionSet_.type).get(AbstractJpaBaseEntity_.id), typeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet} for given id collection of {@link DistributionSet#getType()}.
|
||||
*
|
||||
* @param typeIds id collection of distribution set type to search
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> hasType(final Collection<Long> typeIds) {
|
||||
return (dsRoot, query, cb) -> dsRoot.get(JpaDistributionSet_.type).get(AbstractJpaBaseEntity_.id).in(typeIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by tag.
|
||||
*
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Utility class for {@link JpaDistributionSetTag}s {@link Specification}s. The class provides Spring Data JPQL Specifications.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class DistributionSetTagSpecifications {
|
||||
|
||||
public static Specification<JpaDistributionSetTag> byName(@NotEmpty final String name) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(AbstractJpaNamedEntity_.name), name);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTypeEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
@@ -18,25 +20,11 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link DistributionSetType}s. The class provides
|
||||
* Spring Data JPQL Specifications.
|
||||
* Specifications class for {@link DistributionSetType}s. The class provides Spring Data JPQL Specifications.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class DistributionSetTypeSpecification {
|
||||
|
||||
private DistributionSetTypeSpecification() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetType}s with
|
||||
* DELETED attribute <code>false</code> - i.e. is not deleted.
|
||||
*
|
||||
* @return the {@link DistributionSetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetType> isNotDeleted() {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<Boolean> get(JpaDistributionSetType_.deleted), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetType} with
|
||||
* given {@link DistributionSetType#getName()} including fetching the
|
||||
@@ -60,4 +48,4 @@ public final class DistributionSetTypeSpecification {
|
||||
public static Specification<JpaDistributionSetType> byKey(final String key) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(AbstractJpaTypeEntity_.key), key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,91 +11,25 @@ package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import jakarta.persistence.criteria.ListJoin;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedVersionedEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link SoftwareModule}s. The class provides Spring
|
||||
* Data JPQL Specifications
|
||||
* Specifications class for {@link SoftwareModule}s. The class provides Spring Data JPQL Specifications
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SoftwareModuleSpecification {
|
||||
|
||||
private SoftwareModuleSpecification() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link SoftwareModule} with given
|
||||
* {@link DistributionSet#getId()}.
|
||||
*
|
||||
* @param swModuleId to search
|
||||
* @return the {@link SoftwareModule} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaSoftwareModule> byId(final Long swModuleId) {
|
||||
return (swRoot, query, cb) -> cb.equal(swRoot.get(AbstractJpaBaseEntity_.id), swModuleId);
|
||||
}
|
||||
|
||||
public static Specification<JpaSoftwareModule> byAssignedToDs(final Long dsId) {
|
||||
return (swRoot, query, cb) -> {
|
||||
final ListJoin<JpaSoftwareModule, JpaDistributionSet> join = swRoot.join(JpaSoftwareModule_.assignedTo);
|
||||
return cb.equal(join.get(AbstractJpaBaseEntity_.ID), dsId);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link SoftwareModule}s with
|
||||
* DELETED attribute <code>false</code> - i.e. is not deleted.
|
||||
*
|
||||
* @return the {@link SoftwareModule} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaSoftwareModule> isNotDeleted() {
|
||||
return (swRoot, query, cb) -> cb.equal(swRoot.get(JpaSoftwareModule_.deleted), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link SoftwareModule}s by "like
|
||||
* name and like version".
|
||||
*
|
||||
* @param name to be filtered on
|
||||
* @param version to be filtered on
|
||||
* @return the {@link SoftwareModule} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaSoftwareModule> likeNameAndVersion(final String name, final String version) {
|
||||
return (smRoot, query, cb) -> cb.and(
|
||||
cb.like(cb.lower(smRoot.get(AbstractJpaNamedEntity_.name)), name.toLowerCase()),
|
||||
cb.like(cb.lower(smRoot.get(AbstractJpaNamedVersionedEntity_.version)), version.toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link SoftwareModule}s by "like
|
||||
* name or like version".
|
||||
*
|
||||
* @param type to be filtered on
|
||||
* @return the {@link SoftwareModule} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaSoftwareModule> equalType(final Long type) {
|
||||
return (smRoot, query, cb) -> cb.equal(
|
||||
smRoot.get(JpaSoftwareModule_.type).get(AbstractJpaBaseEntity_.id), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for fetching {@link SoftwareModule}s type.
|
||||
*
|
||||
* @return the {@link SoftwareModule} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaSoftwareModule> fetchType() {
|
||||
return (smRoot, query, cb) -> {
|
||||
if (!query.getResultType().isAssignableFrom(Long.class)) {
|
||||
smRoot.fetch(JpaSoftwareModule_.type);
|
||||
}
|
||||
return cb.conjunction();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType_;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link SoftwareModuleType}s. The class provides
|
||||
* Spring Data JPQL Specifications.
|
||||
*/
|
||||
public class SoftwareModuleTypeSpecification {
|
||||
|
||||
private SoftwareModuleTypeSpecification() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link SoftwareModuleType}s with
|
||||
* DELETED attribute <code>false</code> - i.e. is not deleted.
|
||||
*
|
||||
* @return the {@link SoftwareModuleType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaSoftwareModuleType> isNotDeleted() {
|
||||
return (root, query, cb) -> cb.equal(root.get(JpaSoftwareModuleType_.deleted), false);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import jakarta.persistence.criteria.Join;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link org.eclipse.hawkbit.repository.model.Tag}s.
|
||||
* The class provides Spring Data JPQL Specifications.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class TagSpecification {
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetTag}s by
|
||||
* assigned {@link DistributionSet}.
|
||||
*
|
||||
* @param dsId of the distribution set
|
||||
* @return the {@link JpaDistributionSetTag} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetTag> ofDistributionSet(final Long dsId) {
|
||||
return (dsRoot, query, criteriaBuilder) -> {
|
||||
final Join<JpaDistributionSetTag, JpaDistributionSet> tagJoin = dsRoot
|
||||
.join(JpaDistributionSetTag_.assignedToDistributionSet);
|
||||
|
||||
query.distinct(true);
|
||||
|
||||
return criteriaBuilder.equal(tagJoin.get(AbstractJpaBaseEntity_.id), dsId);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -16,26 +18,11 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link TargetFilterQuery}s. The class provides
|
||||
* Spring Data JPQL Specifications.
|
||||
* Specifications class for {@link TargetFilterQuery}s. The class provides Spring Data JPQL Specifications.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class TargetFilterQuerySpecification {
|
||||
|
||||
private TargetFilterQuerySpecification() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link JpaTargetFilterQuery}s based
|
||||
* on is {@link JpaTargetFilterQuery#getQuery()}.
|
||||
*
|
||||
* @param queryValue the query of the filter
|
||||
* @return the {@link JpaTargetFilterQuery} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetFilterQuery> equalsQuery(final String queryValue) {
|
||||
return (targetFilterQueryRoot, query, cb) -> cb.equal(targetFilterQueryRoot.get(JpaTargetFilterQuery_.query), queryValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link JpaTargetFilterQuery}s based
|
||||
* on is {@link JpaTargetFilterQuery#getName()}.
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.ListJoin;
|
||||
@@ -27,7 +25,6 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaNamedEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
@@ -108,16 +105,6 @@ public final class TargetSpecifications {
|
||||
return (targetRoot, query, cb) -> targetRoot.get(AbstractJpaBaseEntity_.id).in(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that have the
|
||||
* request controller attributes flag set
|
||||
*
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasRequestControllerAttributesTrue() {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.requestControllerAttributes), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link JpaTarget}s including {@link JpaTarget#getAssignedDistributionSet()}.
|
||||
*
|
||||
@@ -132,26 +119,6 @@ public final class TargetSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "equal to any given {@link TargetUpdateStatus}".
|
||||
*
|
||||
* @param updateStatus to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetUpdateStatus(final Collection<TargetUpdateStatus> updateStatus) {
|
||||
return (targetRoot, query, cb) -> targetRoot.get(JpaTarget_.updateStatus).in(updateStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "equal to given {@link TargetUpdateStatus}".
|
||||
*
|
||||
* @param updateStatus to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetUpdateStatus(final TargetUpdateStatus updateStatus) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.updateStatus), updateStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "not equal to given {@link TargetUpdateStatus}".
|
||||
*
|
||||
@@ -162,36 +129,6 @@ public final class TargetSpecifications {
|
||||
return (targetRoot, query, cb) -> cb.not(cb.equal(targetRoot.get(JpaTarget_.updateStatus), updateStatus));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that are overdue. A target is overdue if it did not respond during the configured
|
||||
* intervals:<br>
|
||||
* <em>poll_itvl + overdue_itvl</em>
|
||||
*
|
||||
* @param overdueTimestamp the calculated timestamp to compare with the last response of a target (lastTargetQuery).<br>
|
||||
* The <code>overdueTimestamp</code> has to be calculated with the following expression:<br>
|
||||
* <em>overdueTimestamp = nowTimestamp - poll_itvl - overdue_itvl</em>
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> isOverdue(final long overdueTimestamp) {
|
||||
return (targetRoot, query, cb) ->
|
||||
cb.lessThanOrEqualTo(targetRoot.get(JpaTarget_.lastTargetQuery), overdueTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "like controllerId or like name".
|
||||
*
|
||||
* @param searchText to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> likeControllerIdOrName(final String searchText) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final String searchTextToLower = searchText.toLowerCase();
|
||||
return cb.or(
|
||||
cb.like(cb.lower(targetRoot.get(JpaTarget_.controllerId)), searchTextToLower),
|
||||
cb.like(cb.lower(targetRoot.get(AbstractJpaNamedEntity_.name)), searchTextToLower));
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<JpaTarget> eqTargetGroup(final String targetGroup) {
|
||||
return (targetRoot, query, criteriaBuilder) -> {
|
||||
final String groupTextToLower = targetGroup.toLowerCase();
|
||||
@@ -208,16 +145,6 @@ public final class TargetSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "like controllerId".
|
||||
*
|
||||
* @param distributionId to be filtered on
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasInstalledOrAssignedDistributionSet(@NotNull final Long distributionId) {
|
||||
return hasInstalledDistributionSet(distributionId).or(hasAssignedDistributionSet(distributionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all targets by given {@link Target#getControllerId()}s and which are not yet assigned to given {@link DistributionSet}.
|
||||
*
|
||||
@@ -225,42 +152,14 @@ public final class TargetSpecifications {
|
||||
* @param distributionId set that is not yet assigned
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasControllerIdAndAssignedDistributionSetIdNot(final List<String> tIDs,
|
||||
@NotNull final Long distributionId) {
|
||||
public static Specification<JpaTarget> hasControllerIdAndAssignedDistributionSetIdNot(
|
||||
final List<String> tIDs, @NotNull final Long distributionId) {
|
||||
return (targetRoot, query, cb) -> cb.and(targetRoot.get(JpaTarget_.controllerId).in(tIDs),
|
||||
cb.or(
|
||||
cb.notEqual(targetRoot.get(JpaTarget_.assignedDistributionSet).get(AbstractJpaBaseEntity_.id), distributionId),
|
||||
cb.isNull(targetRoot.get(JpaTarget_.assignedDistributionSet))));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s based on a {@link TargetTag} name.
|
||||
*
|
||||
* @param tagName to search for
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTagName(final String tagName) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaTarget, JpaTargetTag> join = targetRoot.join(JpaTarget_.tags);
|
||||
return cb.equal(join.get(AbstractJpaNamedEntity_.name), tagName);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by "has no tag names"or "has at least on of the given tag names".
|
||||
*
|
||||
* @param tagNames to be filtered on
|
||||
* @param selectTargetWithNoTag flag to get targets with no tag assigned
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTags(final String[] tagNames, final Boolean selectTargetWithNoTag) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Predicate predicate = getHasTagsPredicate(targetRoot, cb, selectTargetWithNoTag, tagNames);
|
||||
query.distinct(true);
|
||||
return predicate;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by assigned distribution set.
|
||||
*
|
||||
@@ -297,7 +196,7 @@ public final class TargetSpecifications {
|
||||
public static Specification<JpaTarget> isCompatibleWithDistributionSetType(final Long distributionSetTypeId) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
// Since the targetRoot is changed by joining we need to get the isNull predicate first
|
||||
final Predicate targetTypeIsNull = getTargetTypeIsNullPredicate(targetRoot);
|
||||
final Predicate targetTypeIsNull = targetRoot.get(JpaTarget_.targetType).isNull();
|
||||
return cb.or(targetTypeIsNull, cb.equal(getDsTypeIdPath(targetRoot), distributionSetTypeId));
|
||||
};
|
||||
}
|
||||
@@ -409,36 +308,6 @@ public final class TargetSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by target type id
|
||||
*
|
||||
* @param typeId the id of the target type
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetType(final long typeId) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.targetType).get(AbstractJpaBaseEntity_.id), typeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by target type id is equal to null
|
||||
*
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasNoTargetType() {
|
||||
return (targetRoot, query, cb) -> cb.isNull(targetRoot.get(JpaTarget_.targetType));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that don't have target type assigned
|
||||
*
|
||||
* @param typeId the id of the target type
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetTypeNot(final Long typeId) {
|
||||
return (targetRoot, query, cb) -> cb.or(getTargetTypeIsNullPredicate(targetRoot),
|
||||
cb.notEqual(targetRoot.get(JpaTarget_.targetType).get(AbstractJpaBaseEntity_.id), typeId));
|
||||
}
|
||||
|
||||
public static Specification<JpaTarget> failedActionsForRollout(final String rolloutId) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Join<JpaTarget, Action> targetActions = targetRoot.join("actions");
|
||||
@@ -461,35 +330,6 @@ public final class TargetSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
private static Predicate getHasTagsPredicate(final Root<JpaTarget> targetRoot, final CriteriaBuilder cb,
|
||||
final Boolean selectTargetWithNoTag, final String[] tagNames) {
|
||||
final SetJoin<JpaTarget, JpaTargetTag> tags = targetRoot.join(JpaTarget_.tags, JoinType.LEFT);
|
||||
final Path<String> exp = tags.get(AbstractJpaNamedEntity_.name);
|
||||
|
||||
final List<Predicate> hasTagsPredicates = new ArrayList<>();
|
||||
if (isNoTagActive(selectTargetWithNoTag)) {
|
||||
hasTagsPredicates.add(exp.isNull());
|
||||
}
|
||||
if (isAtLeastOneTagActive(tagNames)) {
|
||||
hasTagsPredicates.add(exp.in((Object[]) tagNames));
|
||||
}
|
||||
|
||||
return hasTagsPredicates.stream().reduce(cb::or)
|
||||
.orElseThrow(() -> new RuntimeException("Neither NO_TAG, nor TAG target tag filter was provided!"));
|
||||
}
|
||||
|
||||
private static boolean isNoTagActive(final Boolean selectTargetWithNoTag) {
|
||||
return Boolean.TRUE.equals(selectTargetWithNoTag);
|
||||
}
|
||||
|
||||
private static boolean isAtLeastOneTagActive(final String[] tagNames) {
|
||||
return tagNames != null && tagNames.length > 0;
|
||||
}
|
||||
|
||||
private static Predicate getTargetTypeIsNullPredicate(final Root<JpaTarget> targetRoot) {
|
||||
return targetRoot.get(JpaTarget_.targetType).isNull();
|
||||
}
|
||||
|
||||
private static Path<Long> getDsTypeIdPath(final Root<JpaTarget> root) {
|
||||
final Join<JpaTarget, JpaTargetType> targetTypeJoin = root.join(JpaTarget_.targetType, JoinType.LEFT);
|
||||
return targetTypeJoin.join(JpaTargetType_.distributionSetTypes, JoinType.LEFT).get(AbstractJpaBaseEntity_.id);
|
||||
|
||||
@@ -31,16 +31,6 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class TargetTypeSpecification {
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by controllerId
|
||||
*
|
||||
* @param ids to search for
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> hasIdIn(final Collection<Long> ids) {
|
||||
return (targetRoot, query, cb) -> targetRoot.get(AbstractJpaBaseEntity_.id).in(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s based on a {@link DistributionSetType} name.
|
||||
*
|
||||
@@ -73,14 +63,4 @@ public final class TargetTypeSpecification {
|
||||
public static Specification<JpaTargetType> hasName(final String name) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(AbstractJpaNamedEntity_.name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link TargetType}s by "like name".
|
||||
*
|
||||
* @param name to be filtered on
|
||||
* @return the {@link TargetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetType> likeName(final String name) {
|
||||
return (targetRoot, query, cb) -> cb.like(cb.lower(targetRoot.get(AbstractJpaNamedEntity_.name)), name.toLowerCase());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user