Fix portable event on setting confirmation status (#2146)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -15,6 +15,8 @@ import java.util.Optional;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.NoCountSliceRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
@@ -32,13 +34,12 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* A collection of static helper methods for the management classes
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class JpaManagementHelper {
|
||||
|
||||
private JpaManagementHelper() {
|
||||
}
|
||||
|
||||
public static <T, J extends T> Optional<J> findOneBySpec(final JpaSpecificationExecutor<J> repository,
|
||||
final List<Specification<J>> specList) {
|
||||
public static <T, J extends T> Optional<J> findOneBySpec(
|
||||
final JpaSpecificationExecutor<J> repository, final List<Specification<J>> specList) {
|
||||
return repository.findOne(combineWithAnd(specList));
|
||||
}
|
||||
|
||||
@@ -84,8 +85,8 @@ public final class JpaManagementHelper {
|
||||
return repository.count(combineWithAnd(specList));
|
||||
}
|
||||
|
||||
public static <J extends AbstractJpaBaseEntity> J touch(final EntityManager entityManager,
|
||||
final CrudRepository<J, ?> repository, final J entity) {
|
||||
public static <J extends AbstractJpaBaseEntity> J touch(
|
||||
final EntityManager entityManager, final CrudRepository<J, ?> repository, final J entity) {
|
||||
// merge base entity so optLockRevision gets updated and audit
|
||||
// log written because modifying e.g. metadata is modifying the base
|
||||
// entity itself for auditing purposes.
|
||||
|
||||
@@ -835,9 +835,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
ConfirmationManagement confirmationManagement(final TargetRepository targetRepository,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
final EntityManager entityManager, final EntityFactory entityFactory) {
|
||||
return new JpaConfirmationManagement(targetRepository, actionRepository, actionStatusRepository,
|
||||
repositoryProperties, quotaManagement, entityFactory);
|
||||
repositoryProperties, quotaManagement, entityManager, entityFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,8 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
@@ -25,6 +27,7 @@ import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.AutoConfirmationAlreadyActiveException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidConfirmationFeedbackException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
@@ -56,6 +59,7 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
|
||||
public static final String CONFIRMATION_CODE_MSG_PREFIX = "Confirmation status code: %d";
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final EntityFactory entityFactory;
|
||||
private final TargetRepository targetRepository;
|
||||
|
||||
@@ -63,9 +67,10 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
final TargetRepository targetRepository,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
final EntityManager entityManager, final EntityFactory entityFactory) {
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
this.targetRepository = targetRepository;
|
||||
this.entityManager = entityManager;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@@ -86,6 +91,8 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
}
|
||||
final JpaAutoConfirmationStatus confirmationStatus = new JpaAutoConfirmationStatus(initiator, remark, target);
|
||||
target.setAutoConfirmationStatus(confirmationStatus);
|
||||
// since the status is not part of the JpaTarget table (just ref) it might be needed to touch the entity to have updated lastModifiedAt
|
||||
JpaManagementHelper.touch(entityManager, targetRepository, target);
|
||||
final JpaTarget updatedTarget = targetRepository.save(target);
|
||||
final AutoConfirmationStatus autoConfStatus = updatedTarget.getAutoConfirmationStatus();
|
||||
if (autoConfStatus == null) {
|
||||
@@ -159,6 +166,8 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
log.debug("Deactivate auto confirmation for controllerId '{}'", controllerId);
|
||||
final JpaTarget target = targetRepository.getByControllerId(controllerId);
|
||||
target.setAutoConfirmationStatus(null);
|
||||
// since the status is not part of the JpaTarget table (just ref) it might be needed to touch the entity to have updated lastModifiedAt
|
||||
JpaManagementHelper.touch(entityManager, targetRepository, target);
|
||||
targetRepository.save(target);
|
||||
}
|
||||
|
||||
|
||||
@@ -740,8 +740,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
final Long dsId, final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
||||
final RetryCallback<DistributionSetAssignmentResult, ConcurrencyFailureException> retryCallback =
|
||||
retryContext -> assignDistributionSetToTargets(
|
||||
initiatedBy, dsId, targetsWithActionType, actionMessage, assignmentStrategy);
|
||||
retryContext -> assignDistributionSetToTargets(initiatedBy, dsId, targetsWithActionType, actionMessage, assignmentStrategy);
|
||||
return retryTemplate.execute(retryCallback);
|
||||
}
|
||||
|
||||
@@ -764,10 +763,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
* @param actionMessage an optional message to be written into the action status
|
||||
* @param assignmentStrategy the assignment strategy (online /offline)
|
||||
* @return the assignment result
|
||||
* @throws IncompleteDistributionSetException if mandatory {@link SoftwareModuleType} are not assigned as
|
||||
* define by the {@link DistributionSetType}.
|
||||
* @throws IncompleteDistributionSetException if mandatory {@link SoftwareModuleType} are not assigned as define by the
|
||||
* {@link DistributionSetType}.
|
||||
*/
|
||||
private DistributionSetAssignmentResult assignDistributionSetToTargets(final String initiatedBy, final Long dsId,
|
||||
private DistributionSetAssignmentResult assignDistributionSetToTargets(
|
||||
final String initiatedBy, final Long dsId,
|
||||
final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
||||
final JpaDistributionSet distributionSet = (JpaDistributionSet) distributionSetManagement.getValidAndComplete(dsId);
|
||||
@@ -780,28 +780,28 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
});
|
||||
}
|
||||
|
||||
final List<String> providedTargetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId)
|
||||
.distinct().toList();
|
||||
final List<String> providedTargetIds = targetsWithActionType.stream()
|
||||
.map(TargetWithActionType::getControllerId)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
final List<String> existingTargetIds = ListUtils.partition(providedTargetIds, Constants.MAX_ENTRIES_IN_STATEMENT)
|
||||
.stream()
|
||||
.map(ids -> targetRepository.findAll(AccessController.Operation.UPDATE,
|
||||
TargetSpecifications.hasControllerIdIn(ids)))
|
||||
.flatMap(List::stream).map(JpaTarget::getControllerId).toList();
|
||||
|
||||
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds,
|
||||
distributionSet.getId());
|
||||
.map(ids -> targetRepository.findAll(AccessController.Operation.UPDATE, TargetSpecifications.hasControllerIdIn(ids)))
|
||||
.flatMap(List::stream).map(JpaTarget::getControllerId)
|
||||
.toList();
|
||||
|
||||
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds, distributionSet.getId());
|
||||
if (targetEntities.isEmpty()) {
|
||||
return allTargetsAlreadyAssignedResult(distributionSet, existingTargetIds.size());
|
||||
}
|
||||
|
||||
final List<TargetWithActionType> existingTargetsWithActionType = targetsWithActionType.stream()
|
||||
.filter(target -> existingTargetIds.contains(target.getControllerId())).toList();
|
||||
.filter(target -> existingTargetIds.contains(target.getControllerId()))
|
||||
.toList();
|
||||
|
||||
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(initiatedBy,
|
||||
existingTargetsWithActionType, actionMessage, assignmentStrategy, distributionSet,
|
||||
targetEntities);
|
||||
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(
|
||||
initiatedBy, existingTargetsWithActionType, actionMessage, assignmentStrategy, distributionSet, targetEntities);
|
||||
return buildAssignmentResult(distributionSet, assignedActions, existingTargetsWithActionType.size());
|
||||
}
|
||||
|
||||
@@ -824,17 +824,14 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
closeOrCancelActiveActions(assignmentStrategy, targetEntitiesIdsChunks);
|
||||
}
|
||||
// cancel all scheduled actions which are in-active, these actions were
|
||||
// not active before and the manual assignment which has been done
|
||||
// cancels them
|
||||
// not active before and the manual assignment which has been done cancels them
|
||||
targetEntitiesIdsChunks.forEach(this::cancelInactiveScheduledActionsForTargets);
|
||||
setAssignedDistributionSetAndTargetUpdateStatus(assignmentStrategy, distributionSetEntity,
|
||||
targetEntitiesIdsChunks);
|
||||
final Map<TargetWithActionType, JpaAction> assignedActions = createActions(initiatedBy, targetsWithActionType,
|
||||
targetEntities, assignmentStrategy, distributionSetEntity);
|
||||
// create initial action status when action is created so we remember
|
||||
setAssignedDistributionSetAndTargetUpdateStatus(assignmentStrategy, distributionSetEntity, targetEntitiesIdsChunks);
|
||||
final Map<TargetWithActionType, JpaAction> assignedActions = createActions(
|
||||
targetsWithActionType, targetEntities, distributionSetEntity, assignmentStrategy, initiatedBy);
|
||||
// create initial action status when action is created, so we remember
|
||||
// the initial running status because we will change the status
|
||||
// of the action itself and with this action status we have a nicer
|
||||
// action history.
|
||||
// of the action itself and with this action status we have a nicer action history.
|
||||
createActionsStatus(assignedActions, assignmentStrategy, actionMessage);
|
||||
|
||||
detachEntitiesAndSendTargetUpdatedEvents(distributionSetEntity, targetEntities, assignmentStrategy);
|
||||
@@ -872,12 +869,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
assignmentStrategy.setAssignedDistributionSetAndTargetStatus(set, targetIdsChunks, currentUser);
|
||||
}
|
||||
|
||||
private Map<TargetWithActionType, JpaAction> createActions(final String initiatedBy,
|
||||
final Collection<TargetWithActionType> targetsWithActionType, final List<JpaTarget> targets,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy, final JpaDistributionSet set) {
|
||||
|
||||
private Map<TargetWithActionType, JpaAction> createActions(
|
||||
final Collection<TargetWithActionType> targetsWithActionType, final List<JpaTarget> targets, final JpaDistributionSet set,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy, final String initiatedBy) {
|
||||
final Map<TargetWithActionType, JpaAction> persistedActions = new LinkedHashMap<>();
|
||||
|
||||
for (final TargetWithActionType twt : targetsWithActionType) {
|
||||
final JpaAction targetAction = assignmentStrategy.createTargetAction(initiatedBy, twt, targets, set);
|
||||
if (targetAction != null) {
|
||||
@@ -887,7 +882,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return persistedActions;
|
||||
}
|
||||
|
||||
private void createActionsStatus(final Map<TargetWithActionType, JpaAction> actions,
|
||||
private void createActionsStatus(
|
||||
final Map<TargetWithActionType, JpaAction> actions,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy, final String actionMessage) {
|
||||
actionStatusRepository.saveAll(actions.entrySet().stream().map(entry -> {
|
||||
final JpaAction action = entry.getValue();
|
||||
|
||||
@@ -88,22 +88,19 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> getByKey(final String key) {
|
||||
return distributionSetTypeRepository
|
||||
.findOne(DistributionSetTypeSpecification.byKey(key)).map(DistributionSetType.class::cast);
|
||||
return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byKey(key)).map(DistributionSetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> getByName(final String name) {
|
||||
return distributionSetTypeRepository
|
||||
.findOne(DistributionSetTypeSpecification.byName(name)).map(DistributionSetType.class::cast);
|
||||
return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byName(name)).map(DistributionSetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType assignOptionalSoftwareModuleTypes(final long id,
|
||||
final Collection<Long> softwareModulesTypeIds) {
|
||||
public DistributionSetType assignOptionalSoftwareModuleTypes(final long id, final Collection<Long> softwareModulesTypeIds) {
|
||||
return assignSoftwareModuleTypes(id, softwareModulesTypeIds, false);
|
||||
}
|
||||
|
||||
@@ -111,8 +108,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Transactional
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType assignMandatorySoftwareModuleTypes(final long id,
|
||||
final Collection<Long> softwareModuleTypeIds) {
|
||||
public DistributionSetType assignMandatorySoftwareModuleTypes(final long id, final Collection<Long> softwareModuleTypeIds) {
|
||||
return assignSoftwareModuleTypes(id, softwareModuleTypeIds, true);
|
||||
}
|
||||
|
||||
@@ -122,11 +118,8 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType unassignSoftwareModuleType(final long id, final long softwareModuleTypeId) {
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(id);
|
||||
|
||||
checkDistributionSetTypeNotAssigned(id);
|
||||
|
||||
type.removeModuleType(softwareModuleTypeId);
|
||||
|
||||
return distributionSetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
@@ -135,9 +128,9 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSetType> create(final Collection<DistributionSetTypeCreate> types) {
|
||||
final List<JpaDistributionSetType> typesToCreate = types.stream().map(JpaDistributionSetTypeCreate.class::cast)
|
||||
final List<JpaDistributionSetType> typesToCreate = types.stream()
|
||||
.map(JpaDistributionSetTypeCreate.class::cast)
|
||||
.map(JpaDistributionSetTypeCreate::build).toList();
|
||||
|
||||
return Collections.unmodifiableList(
|
||||
distributionSetTypeRepository.saveAll(AccessController.Operation.CREATE, typesToCreate));
|
||||
}
|
||||
@@ -148,7 +141,6 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType create(final DistributionSetTypeCreate c) {
|
||||
final JpaDistributionSetType distributionSetType = ((JpaDistributionSetTypeCreate) c).build();
|
||||
|
||||
return distributionSetTypeRepository.save(AccessController.Operation.CREATE, distributionSetType);
|
||||
}
|
||||
|
||||
@@ -158,9 +150,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType update(final DistributionSetTypeUpdate u) {
|
||||
final GenericDistributionSetTypeUpdate update = (GenericDistributionSetTypeUpdate) u;
|
||||
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(update.getId());
|
||||
|
||||
update.getDescription().ifPresent(type::setDescription);
|
||||
update.getColour().ifPresent(type::setColour);
|
||||
|
||||
@@ -245,13 +235,12 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Override
|
||||
public Page<DistributionSetType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTypeFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTypeFields.class, virtualPropertyReplacer, database),
|
||||
DistributionSetTypeSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
private static void removeModuleTypes(final Collection<Long> currentSmTypeIds,
|
||||
final Collection<Long> updatedSmTypeIds,
|
||||
private static void removeModuleTypes(
|
||||
final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||
final LongFunction<JpaDistributionSetType> removeModuleTypeCallback) {
|
||||
final Set<Long> smTypeIdsToRemove = currentSmTypeIds.stream().filter(id -> !updatedSmTypeIds.contains(id))
|
||||
.collect(Collectors.toSet());
|
||||
@@ -264,10 +253,10 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
return update.getOptional().isPresent() || update.getMandatory().isPresent();
|
||||
}
|
||||
|
||||
private void addModuleTypes(final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||
private void addModuleTypes(
|
||||
final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||
final Function<SoftwareModuleType, JpaDistributionSetType> addModuleTypeCallback) {
|
||||
final Set<Long> smTypeIdsToAdd = updatedSmTypeIds.stream().filter(id -> !currentSmTypeIds.contains(id))
|
||||
.collect(Collectors.toSet());
|
||||
final Set<Long> smTypeIdsToAdd = updatedSmTypeIds.stream().filter(id -> !currentSmTypeIds.contains(id)).collect(Collectors.toSet());
|
||||
if (!CollectionUtils.isEmpty(smTypeIdsToAdd)) {
|
||||
softwareModuleTypeRepository.findAllById(smTypeIdsToAdd).forEach(addModuleTypeCallback::apply);
|
||||
}
|
||||
@@ -275,8 +264,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
private DistributionSetType assignSoftwareModuleTypes(
|
||||
final long dsTypeId, final Collection<Long> softwareModulesTypeIds, final boolean mandatory) {
|
||||
final Collection<JpaSoftwareModuleType> foundModules =
|
||||
softwareModuleTypeRepository.findAllById(softwareModulesTypeIds);
|
||||
final Collection<JpaSoftwareModuleType> foundModules = softwareModuleTypeRepository.findAllById(softwareModulesTypeIds);
|
||||
if (foundModules.size() < softwareModulesTypeIds.size()) {
|
||||
throw new EntityNotFoundException(
|
||||
SoftwareModuleType.class, softwareModulesTypeIds, foundModules.stream().map(SoftwareModuleType::getId).toList());
|
||||
@@ -315,8 +303,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
}
|
||||
|
||||
private JpaDistributionSetType findDistributionSetTypeAndThrowExceptionIfNotFound(final Long setId) {
|
||||
return (JpaDistributionSetType) get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, setId));
|
||||
return (JpaDistributionSetType) get(setId).orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, setId));
|
||||
}
|
||||
|
||||
private void checkDistributionSetTypeNotAssigned(final Long id) {
|
||||
@@ -325,4 +312,4 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
"Distribution set type %s is already assigned to distribution sets and cannot be changed!", id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user