Refactor action repository (#2118)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -13,10 +13,9 @@ import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ON
|
||||
import static org.eclipse.hawkbit.repository.model.Action.Status.ERROR;
|
||||
import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
@@ -25,7 +24,6 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
@@ -34,7 +32,7 @@ import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* Implements utility methods for managing {@link Action}s
|
||||
@@ -104,32 +102,19 @@ public class JpaActionManagement {
|
||||
quotaManagement.getMaxMessagesPerActionStatus(), "Message", ActionStatus.class.getSimpleName(), null);
|
||||
}
|
||||
|
||||
List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
|
||||
final int maxActionCount) {
|
||||
final List<Action> actions = new ArrayList<>();
|
||||
actions.addAll(
|
||||
actionRepository
|
||||
.findAll(
|
||||
ActionSpecifications.byTargetControllerIdAndActiveAndWeightIsNullFetchDS(controllerId, false),
|
||||
PageRequest.of(
|
||||
0, maxActionCount,
|
||||
Sort.by(
|
||||
Sort.Order.desc(JpaAction_.WEIGHT),
|
||||
Sort.Order.asc(JpaAction_.ID))))
|
||||
.getContent());
|
||||
|
||||
actions.addAll(
|
||||
actionRepository
|
||||
.findAll(
|
||||
ActionSpecifications.byTargetControllerIdAndActiveAndWeightIsNullFetchDS(controllerId, true),
|
||||
PageRequest.of(
|
||||
0, maxActionCount,
|
||||
Sort.by(
|
||||
Sort.Order.asc(JpaAction_.ID))))
|
||||
.getContent());
|
||||
final Comparator<Action> actionImportance = Comparator.comparingInt(this::getWeightConsideringDefault)
|
||||
.reversed().thenComparing(Action::getId);
|
||||
return actions.stream().sorted(actionImportance).limit(maxActionCount).collect(Collectors.toList());
|
||||
protected List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId, final int maxActionCount) {
|
||||
final Pageable pageable = PageRequest.of(0, maxActionCount);
|
||||
return Stream.concat(
|
||||
// get the highest actions with weight
|
||||
actionRepository
|
||||
.findFetchDsByTarget_ControllerIdAndActiveIsTrueAndWeightNotNullOrderByWeightDescIdAsc(controllerId, pageable)
|
||||
.stream(),
|
||||
// get the oldest actions without weight
|
||||
actionRepository.findFetchDsByTarget_ControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(controllerId, pageable)
|
||||
.stream())
|
||||
.sorted(Comparator.comparingInt(this::getWeightConsideringDefault).reversed().thenComparing(Action::getId))
|
||||
.limit(maxActionCount)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static boolean isIntermediateStatus(final JpaActionStatus actionStatus) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -32,6 +33,7 @@ import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.Query;
|
||||
@@ -250,8 +252,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
@Override
|
||||
public Map<Long, List<SoftwareModuleMetadata>> findTargetVisibleMetaDataBySoftwareModuleId(final Collection<Long> moduleId) {
|
||||
return softwareModuleMetadataRepository
|
||||
.findBySoftwareModuleIdInAndTargetVisible(
|
||||
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), moduleId, true)
|
||||
.findBySoftwareModuleIdInAndTargetVisible(moduleId, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT))
|
||||
.getContent().stream()
|
||||
.collect(Collectors.groupingBy(o -> (Long) o[0], Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList())));
|
||||
}
|
||||
@@ -280,14 +281,23 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
return addActionStatus((JpaActionStatusCreate) statusCreate);
|
||||
}
|
||||
|
||||
private static final Pageable PAGEABLE_1 = PageRequest.of(0, 1);
|
||||
|
||||
@Override
|
||||
public Optional<Action> findActiveActionWithHighestWeight(final String controllerId) {
|
||||
return findActiveActionsWithHighestWeight(controllerId, 1).stream().findFirst();
|
||||
return Stream.concat(
|
||||
// get the highest action with weight
|
||||
actionRepository
|
||||
.findByTarget_ControllerIdAndActiveIsTrueAndWeightNotNullOrderByWeightDescIdAsc(controllerId, PAGEABLE_1)
|
||||
.stream(),
|
||||
// get the oldest action without weight
|
||||
actionRepository.findByTarget_ControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(controllerId, PAGEABLE_1).stream())
|
||||
.min(Comparator.comparingInt(this::getWeightConsideringDefault).reversed().thenComparing(Action::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> findActiveActionsWithHighestWeight(final String controllerId, final int maxActionCount) {
|
||||
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
||||
return super.findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -453,7 +463,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
|
||||
@Override
|
||||
public Optional<Target> get(final long targetId) {
|
||||
return targetRepository.findById(targetId).map(t -> (Target) t);
|
||||
return targetRepository.findById(targetId).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -463,18 +473,16 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// For negative and large value of messageCount, limit the number of
|
||||
// messages.
|
||||
// For negative and large value of messageCount, limit the number of messages.
|
||||
final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT
|
||||
? RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT
|
||||
: messageCount;
|
||||
|
||||
final PageRequest pageable = PageRequest.of(0, limit, Sort.by(Direction.DESC, "occurredAt"));
|
||||
final Page<String> messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(pageable, actionId,
|
||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "%");
|
||||
final Page<String> messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(
|
||||
actionId, RepositoryConstants.SERVER_MESSAGE_PREFIX + "%", pageable);
|
||||
|
||||
log.debug("Retrieved {} message(s) from action history for action {}.", messages.getNumberOfElements(),
|
||||
actionId);
|
||||
log.debug("Retrieved {} message(s) from action history for action {}.", messages.getNumberOfElements(), actionId);
|
||||
|
||||
return messages.getContent();
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
|
||||
if (!rolloutGroupIds.isEmpty()) {
|
||||
final List<TotalTargetCountActionStatus> resultList = actionRepository
|
||||
.getStatusCountByRolloutGroupId(rolloutGroupIds);
|
||||
.getStatusCountByRolloutGroupIds(rolloutGroupIds);
|
||||
final Map<Long, List<TotalTargetCountActionStatus>> fromDb = resultList.stream()
|
||||
.collect(Collectors.groupingBy(TotalTargetCountActionStatus::getId));
|
||||
|
||||
|
||||
@@ -711,8 +711,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!rolloutIds.isEmpty()) {
|
||||
final List<TotalTargetCountActionStatus> resultList = actionRepository
|
||||
.getStatusCountByRolloutId(rolloutIds);
|
||||
final List<TotalTargetCountActionStatus> resultList = actionRepository.getStatusCountByRolloutIds(rolloutIds);
|
||||
final Map<Long, List<TotalTargetCountActionStatus>> fromDb = resultList.stream()
|
||||
.collect(Collectors.groupingBy(TotalTargetCountActionStatus::getId));
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return JpaManagementHelper.convertPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
|
||||
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), id, true), pageable);
|
||||
id, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT)), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -486,6 +486,14 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
return softwareModuleMetadataRepository.save(metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, List<SoftwareModuleMetadata>> findMetaDataBySoftwareModuleIdsAndTargetVisible(final Collection<Long> moduleIds) {
|
||||
return softwareModuleMetadataRepository
|
||||
.findBySoftwareModuleIdInAndTargetVisible(moduleIds, true, PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT))
|
||||
.getContent().stream()
|
||||
.collect(Collectors.groupingBy(o -> (Long) o[0], Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList())));
|
||||
}
|
||||
|
||||
private static Stream<JpaSoftwareModuleMetadataCreate> createJpaMetadataCreateStream(
|
||||
final Collection<SoftwareModuleMetadataCreate> create) {
|
||||
return create.stream().map(JpaSoftwareModuleMetadataCreate.class::cast);
|
||||
|
||||
@@ -83,15 +83,14 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
|
||||
@CollectionTable(
|
||||
name = "sp_action_status_messages",
|
||||
joinColumns = @JoinColumn(
|
||||
name = "action_status_id", insertable = false, updatable = false, nullable = false,
|
||||
name = "action_status_id", nullable = false,
|
||||
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_stat_msg_act_stat")),
|
||||
indexes = {
|
||||
@Index(name = "sp_idx_action_status_msgs_01", columnList = "action_status_id") })
|
||||
@Column(name = "detail_message", length = MESSAGE_ENTRY_LENGTH, nullable = false, insertable = false, updatable = false)
|
||||
indexes = { @Index(name = "sp_idx_action_status_msgs_01", columnList = "action_status_id") })
|
||||
@Column(name = "detail_message", length = MESSAGE_ENTRY_LENGTH, nullable = false)
|
||||
private List<String> messages;
|
||||
|
||||
@Setter
|
||||
@Column(name = "code", nullable = true, updatable = false)
|
||||
@Column(name = "code", updatable = false)
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
@@ -69,6 +70,8 @@ import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||
import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
|
||||
import org.eclipse.persistence.queries.UpdateObjectQuery;
|
||||
import org.hibernate.event.spi.PreUpdateEvent;
|
||||
import org.hibernate.event.spi.PreUpdateEventListener;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link Target}.
|
||||
@@ -174,12 +177,12 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
// no cascade option on an ElementCollection, the target objects are always persisted, merged, removed with their parent.
|
||||
@Getter
|
||||
@ElementCollection
|
||||
@Column(name = "attribute_value", length = Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE)
|
||||
@MapKeyColumn(name = "attribute_key", nullable = false, length = Target.CONTROLLER_ATTRIBUTE_KEY_SIZE)
|
||||
@CollectionTable(
|
||||
name = "sp_target_attributes",
|
||||
joinColumns = { @JoinColumn(name = "target_id", nullable = false, insertable = false, updatable = false) },
|
||||
joinColumns = { @JoinColumn(name = "target_id", nullable = false) },
|
||||
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
|
||||
@Column(name = "attribute_value", length = Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE)
|
||||
@MapKeyColumn(name = "attribute_key", length = Target.CONTROLLER_ATTRIBUTE_KEY_SIZE)
|
||||
private Map<String, String> controllerAttributes;
|
||||
|
||||
@OneToMany(mappedBy = "target", fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }, targetEntity = JpaTargetMetadata.class)
|
||||
@@ -331,7 +334,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
/**
|
||||
* Listens to updates on {@link JpaTarget} entities, Filtering out updates that only change the "lastTargetQuery" or "address" fields.
|
||||
*/
|
||||
public static class EntityPropertyChangeListener extends DescriptorEventAdapter {
|
||||
public static class EntityPropertyChangeListener extends DescriptorEventAdapter implements PreUpdateEventListener {
|
||||
|
||||
private static final List<String> TARGET_UPDATE_EVENT_IGNORE_FIELDS = List.of(
|
||||
"lastTargetQuery", "address", // actual to be skipped
|
||||
@@ -346,5 +349,21 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
doNotify(() -> ((EventAwareEntity) object).fireUpdateEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreUpdate(final PreUpdateEvent event) {
|
||||
final Object[] oldState = event.getOldState();
|
||||
final Object[] newState = event.getState();
|
||||
for (int i = 0; i < newState.length; i++) {
|
||||
if (!Objects.equals(oldState[i], newState[i])) {
|
||||
final String attribute = event.getPersister().getAttributeMapping(i).getAttributeName();
|
||||
if (!TARGET_UPDATE_EVENT_IGNORE_FIELDS.contains(attribute)) {
|
||||
doNotify(() -> ((EventAwareEntity) event.getEntity()).fireUpdateEvent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,15 +52,22 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
* @param targetId the action belongs to
|
||||
* @param dsId of the ds that is assigned to the target
|
||||
* @param status of the action
|
||||
* @return action if there is one with assigned target and assigned
|
||||
* {@link DistributionSet}.
|
||||
* @return action if there is one with assigned target and assigned {@link DistributionSet}.
|
||||
*/
|
||||
Optional<Action> findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(@Param("target") long targetId,
|
||||
@Param("ds") Long dsId, @Param("status") Action.Status status);
|
||||
Optional<Action> findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(
|
||||
@Param("target") long targetId, @Param("ds") Long dsId, @Param("status") Action.Status status);
|
||||
|
||||
List<Action> findByTarget_ControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(String controllerId, Pageable pageable);
|
||||
List<Action> findByTarget_ControllerIdAndActiveIsTrueAndWeightNotNullOrderByWeightDescIdAsc(String controllerId, Pageable pageable);
|
||||
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
List<Action> findFetchDsByTarget_ControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(String controllerId, Pageable pageable);
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
List<Action> findFetchDsByTarget_ControllerIdAndActiveIsTrueAndWeightNotNullOrderByWeightDescIdAsc(String controllerId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Switches the status of actions from one specific status into another, only if
|
||||
* the actions are in a specific status. This should be a atomic operation.
|
||||
* Switches the status of actions from one specific status into another, only if the actions are in a specific status. This should be
|
||||
* an atomic operation.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
@@ -72,7 +79,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaAction a SET a.status = :statusToSet WHERE a.target.id IN :targetsIds AND a.active = :active AND a.status = :currentStatus AND a.distributionSet.requiredMigrationStep = false")
|
||||
void switchStatus(@Param("statusToSet") Action.Status statusToSet, @Param("targetsIds") List<Long> targetIds,
|
||||
void switchStatus(
|
||||
@Param("statusToSet") Action.Status statusToSet, @Param("targetsIds") List<Long> targetIds,
|
||||
@Param("active") boolean active, @Param("currentStatus") Action.Status currentStatus);
|
||||
|
||||
/**
|
||||
@@ -124,8 +132,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
Long countByDistributionSetIdAndActiveIsTrue(Long distributionSet);
|
||||
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet
|
||||
* that are not in a given state.
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet that are not in a given state.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
@@ -136,43 +143,39 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
Long countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(Long distributionSet, Status status);
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout and rolloutgroup which
|
||||
* are currently not in the given status. An in-clause statement does not
|
||||
* work with the spring-data, so this is specific usecase regarding to the
|
||||
* rollout-management to find out actions which are not in specific states.
|
||||
* Counts all actions referring to a given rollout and rolloutgroup which are currently not in the given status. An in-clause statement
|
||||
* does not work with the spring-data, so this is specific usecase regarding the rollout-management to find out actions which are not in
|
||||
* specific states.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rollout the rollout the actions are belong to
|
||||
* @param rolloutGroup the rolloutgroup the actions are belong to
|
||||
* @param rolloutGroup the rollout group the actions are belong to
|
||||
* @param statuses the list of statuses the action should not have
|
||||
* @return the count of actions referring the rollout and rolloutgroup and
|
||||
* are not in given states
|
||||
* @return the count of actions referring the rollout and rollout group and are not in given states
|
||||
*/
|
||||
Long countByRolloutAndRolloutGroupAndStatusNotIn(JpaRollout rollout, JpaRolloutGroup rolloutGroup,
|
||||
List<Status> statuses);
|
||||
Long countByRolloutAndRolloutGroupAndStatusNotIn(JpaRollout rollout, JpaRolloutGroup rolloutGroup, List<Status> statuses);
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout and rolloutgroup.
|
||||
* Counts all actions referring to a given rollout and rollout group.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rollout the rollout the actions belong to
|
||||
* @param rolloutGroup the rolloutgroup the actions belong to
|
||||
* @return the count of actions referring to a rollout and rolloutgroup
|
||||
* @param rolloutGroup the rollout group the actions belong to
|
||||
* @return the count of actions referring to a rollout and rollout group
|
||||
*/
|
||||
Long countByRolloutAndRolloutGroup(JpaRollout rollout, JpaRolloutGroup rolloutGroup);
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout, rolloutgroup and status.
|
||||
* Counts all actions referring to a given rollout, rollout group and status.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId the ID of rollout the actions belong to
|
||||
* @param rolloutGroupId the ID rolloutgroup the actions belong to
|
||||
* @param rolloutGroupId the ID rollout group the actions belong to
|
||||
* @param status the status the actions should have
|
||||
* @return the count of actions referring to a rollout, rolloutgroup and are
|
||||
* in a given status
|
||||
* @return the count of actions referring to a rollout, rollout group and are in a given status
|
||||
*/
|
||||
Long countByRolloutIdAndRolloutGroupIdAndStatus(Long rolloutId, Long rolloutGroupId, Action.Status status);
|
||||
|
||||
@@ -189,50 +192,43 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
Long countByRolloutIdAndStatus(Long rolloutId, Action.Status status);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise {@code false}
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId the ID of the rollout the actions belong to
|
||||
* @return {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
* @return {@code true} if actions for the given rollout exists, otherwise {@code false}
|
||||
*/
|
||||
@Query("SELECT CASE WHEN COUNT(a)>0 THEN 'true' ELSE 'false' END FROM JpaAction a WHERE a.rollout.id=:rolloutId")
|
||||
boolean existsByRolloutId(@Param("rolloutId") Long rolloutId);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise {@code false}
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId the ID of the rollout the actions belong to
|
||||
* @param status the action is not to be in
|
||||
* @return {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
* @return {@code true} if actions for the given rollout exists, otherwise {@code false}
|
||||
*/
|
||||
@Query("SELECT CASE WHEN COUNT(a)>0 THEN 'true' ELSE 'false' END FROM JpaAction a WHERE a.rollout.id=:rolloutId AND a.status != :status")
|
||||
boolean existsByRolloutIdAndStatusNotIn(@Param("rolloutId") Long rolloutId, @Param("status") Status status);
|
||||
|
||||
/**
|
||||
* Retrieving all actions referring to a given rollout with a specific action as
|
||||
* parent reference and a specific status.
|
||||
* Retrieving all actions referring to a given rollout with a specific action as parent reference and a specific status.
|
||||
* <p/>
|
||||
* Finding all actions of a specific rolloutgroup parent relation.
|
||||
* Finding all actions of a specific rollout group parent relation.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageable page parameters
|
||||
* @param rollout the rollout the actions belong to
|
||||
* @param rolloutGroupParent the parent rolloutgroup the actions should reference
|
||||
* @param rolloutGroupParent the parent rollout group the actions should reference
|
||||
* @param actionStatus the status the actions have
|
||||
* @return the actions referring a specific rollout and a specific parent
|
||||
* rolloutgroup in a specific status
|
||||
* @return the actions referring a specific rollout and a specific parent rolloutgroup in a specific status
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target", "target.autoConfirmationStatus", "rolloutGroup" }, type = EntityGraphType.LOAD)
|
||||
Page<Action> findByRolloutIdAndRolloutGroupParentIdAndStatus(Pageable pageable, Long rollout,
|
||||
Long rolloutGroupParent, Status actionStatus);
|
||||
Page<Action> findByRolloutIdAndRolloutGroupParentIdAndStatus(Pageable pageable, Long rollout, Long rolloutGroupParent, Status actionStatus);
|
||||
|
||||
/**
|
||||
* Retrieving all actions referring to the first group of a rollout.
|
||||
@@ -242,13 +238,10 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
* @param pageable page parameters
|
||||
* @param rollout the rollout the actions belong to
|
||||
* @param actionStatus the status the actions have
|
||||
* @return the actions referring a specific rollout and a specific parent
|
||||
* rolloutgroup in a specific status
|
||||
* @return the actions referring a specific rollout and a specific parent rolloutgroup in a specific status
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target", "target.autoConfirmationStatus",
|
||||
"rolloutGroup" }, type = EntityGraphType.LOAD)
|
||||
Page<Action> findByRolloutIdAndRolloutGroupParentIsNullAndStatus(Pageable pageable, Long rollout,
|
||||
Status actionStatus);
|
||||
@EntityGraph(attributePaths = { "target", "target.autoConfirmationStatus", "rolloutGroup" }, type = EntityGraphType.LOAD)
|
||||
Page<Action> findByRolloutIdAndRolloutGroupParentIsNullAndStatus(Pageable pageable, Long rollout, Status actionStatus);
|
||||
|
||||
/**
|
||||
* Retrieves all actions for a specific rollout and in a specific status.
|
||||
@@ -263,44 +256,40 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
Page<JpaAction> findByRolloutIdAndStatus(Pageable pageable, Long rolloutId, Status actionStatus);
|
||||
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout.
|
||||
* Get list of objects which has details of status and count of targets in each status in specified rollout.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId id of {@link Rollout}
|
||||
* @return list of objects with status and target count
|
||||
*/
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus( a.rollout.id, a.status , COUNT(a.id)) FROM JpaAction a WHERE a.rollout.id IN ?1 GROUP BY a.rollout.id,a.status")
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutId(List<Long> rolloutId);
|
||||
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId id of {@link Rollout}
|
||||
* @return list of objects with status and target count
|
||||
*/
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus( a.rollout.id, a.status , COUNT(a.id)) FROM JpaAction a WHERE a.rollout.id = ?1 GROUP BY a.rollout.id,a.status")
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rollout.id, a.status, COUNT(a.id)) FROM JpaAction a WHERE a.rollout.id = ?1 GROUP BY a.rollout.id,a.status")
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutId(Long rolloutId);
|
||||
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout group.
|
||||
* Get list of objects which has details of status and count of targets in each status in specified rollout.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId id of {@link Rollout}
|
||||
* @return list of objects with status and target count
|
||||
*/
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rollout.id, a.status, COUNT(a.id)) FROM JpaAction a WHERE a.rollout.id IN ?1 GROUP BY a.rollout.id,a.status")
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutIds(List<Long> rolloutId);
|
||||
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in each status in specified rollout group.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutGroupId id of {@link RolloutGroup}
|
||||
* @return list of objects with status and target count
|
||||
*/
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.id)) FROM JpaAction a WHERE a.rolloutGroup.id = ?1 GROUP BY a.rolloutGroup.id, a.status")
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status, COUNT(a.id)) FROM JpaAction a WHERE a.rolloutGroup.id = ?1 GROUP BY a.rolloutGroup.id, a.status")
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutGroupId(Long rolloutGroupId);
|
||||
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout group.
|
||||
* Get list of objects which has details of status and count of targets in each status in specified rollout group.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
@@ -308,7 +297,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
* @return list of objects with status and target count
|
||||
*/
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.id)) FROM JpaAction a WHERE a.rolloutGroup.id IN ?1 GROUP BY a.rolloutGroup.id, a.status")
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutGroupId(List<Long> rolloutGroupId);
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutGroupIds(List<Long> rolloutGroupId);
|
||||
|
||||
/**
|
||||
* Updates the externalRef of an action by its actionId.
|
||||
@@ -331,4 +320,4 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM JpaAction a WHERE a.id IN ?1")
|
||||
void deleteByIdIn(Collection<Long> actionIDs);
|
||||
}
|
||||
}
|
||||
@@ -52,13 +52,11 @@ public interface ActionStatusRepository extends BaseEntityRepository<JpaActionSt
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageable for page configuration
|
||||
* @param actionId for which to get the status messages
|
||||
* @param filter is the SQL like pattern to use for filtering out or excluding
|
||||
* the messages
|
||||
* @param filter is the SQL like pattern to use for filtering out or excluding the messages
|
||||
* @param pageable for page configuration
|
||||
* @return Page with found status messages.
|
||||
*/
|
||||
@Query("SELECT message FROM JpaActionStatus actionstatus JOIN actionstatus.messages message WHERE actionstatus.action.id = :actionId AND message NOT LIKE :filter")
|
||||
Page<String> findMessagesByActionIdAndMessageNotLike(Pageable pageable, @Param("actionId") Long actionId,
|
||||
@Param("filter") String filter);
|
||||
}
|
||||
Page<String> findMessagesByActionIdAndMessageNotLike(@Param("actionId") Long actionId, @Param("filter") String filter, Pageable pageable);
|
||||
}
|
||||
@@ -133,8 +133,7 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
|
||||
@Override
|
||||
public void deleteByTenant(final String tenant) {
|
||||
if (accessController.getAccessRules(AccessController.Operation.DELETE).isPresent()) {
|
||||
throw new InsufficientPermissionException(
|
||||
"DELETE operation has restriction for given context! deleteAll can't be executed!");
|
||||
throw new InsufficientPermissionException("DELETE operation has restriction for given context! deleteAll can't be executed!");
|
||||
}
|
||||
repository.deleteByTenant(tenant);
|
||||
}
|
||||
@@ -185,8 +184,7 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T, R> R findBy(final Specification<T> spec,
|
||||
final Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
|
||||
public <S extends T, R> R findBy(final Specification<T> spec, final Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
|
||||
return repository.findBy(accessController.appendAccessRules(AccessController.Operation.READ, spec), queryFunction);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,40 +33,37 @@ public interface SoftwareModuleMetadataRepository
|
||||
JpaSpecificationExecutor<JpaSoftwareModuleMetadata> {
|
||||
|
||||
/**
|
||||
* Locates the meta data entries that match the given software module ID and
|
||||
* target visibility flag.
|
||||
* Locates the meta-data entries that match the given software module ID and target visibility flag.
|
||||
*
|
||||
* @param page The pagination parameters.
|
||||
* @param moduleId The ID of the software module.
|
||||
* @param targetVisible The target visibility flag.
|
||||
* @return A {@link Page} with the matching meta data entries.
|
||||
* @param page The pagination parameters.
|
||||
* @return A {@link Page} with the matching meta-data entries.
|
||||
*/
|
||||
Page<JpaSoftwareModuleMetadata> findBySoftwareModuleIdAndTargetVisible(Pageable page, Long moduleId,
|
||||
boolean targetVisible);
|
||||
Page<JpaSoftwareModuleMetadata> findBySoftwareModuleIdAndTargetVisible(
|
||||
@Param("moduleId") Long moduleId, @Param("targetVisible") boolean targetVisible, Pageable page);
|
||||
|
||||
/**
|
||||
* Locates the meta data entries that match the given software module IDs
|
||||
* and target visibility flag.
|
||||
* Locates the meta-data entries that match the given software module IDs and target visibility flag.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param page The pagination parameters.
|
||||
* @param moduleId List of software module IDs.
|
||||
* @param targetVisible The target visibility flag.
|
||||
* @return A {@link Page} with the matching meta data entries.
|
||||
* @param page The pagination parameters.
|
||||
* @return A {@link Page} with the matching meta-data entries.
|
||||
*/
|
||||
@Query("SELECT smd.softwareModule.id, smd FROM JpaSoftwareModuleMetadata smd WHERE smd.softwareModule.id IN :moduleId AND smd.targetVisible = :targetVisible")
|
||||
Page<Object[]> findBySoftwareModuleIdInAndTargetVisible(Pageable page, @Param("moduleId") Collection<Long> moduleId,
|
||||
@Param("targetVisible") boolean targetVisible);
|
||||
Page<Object[]> findBySoftwareModuleIdInAndTargetVisible(
|
||||
@Param("moduleId") Collection<Long> moduleId, @Param("targetVisible") boolean targetVisible, Pageable page);
|
||||
|
||||
/**
|
||||
* Counts the meta data entries that are associated with the addressed
|
||||
* software module.
|
||||
* Counts the meta-data entries that are associated with the addressed software module.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param moduleId The ID of the software module.
|
||||
* @return The number of meta data entries associated with the software module.
|
||||
* @return The number of meta-data entries associated with the software module.
|
||||
*/
|
||||
long countBySoftwareModuleId(@Param("moduleId") Long moduleId);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.ListJoin;
|
||||
import jakarta.persistence.criteria.SetJoin;
|
||||
|
||||
@@ -82,18 +81,13 @@ public final class ActionSpecifications {
|
||||
* Fetches action's distribution set.
|
||||
*
|
||||
* @param controllerId controller id
|
||||
* @param isNull if <code>true</code> return with <code>null</code> weight, otherwise with non-<code>null</code>
|
||||
* @return the matching action s.
|
||||
*/
|
||||
public static Specification<JpaAction> byTargetControllerIdAndActiveAndWeightIsNullFetchDS(final String controllerId,
|
||||
final boolean isNull) {
|
||||
return (root, query, cb) -> {
|
||||
root.fetch(JpaAction_.distributionSet, JoinType.LEFT);
|
||||
return cb.and(
|
||||
public static Specification<JpaAction> byTargetControllerIdAndActive(final String controllerId) {
|
||||
return (root, query, cb) ->
|
||||
cb.and(
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId),
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
isNull ? cb.isNull(root.get(JpaAction_.weight)) : cb.isNotNull(root.get(JpaAction_.weight)));
|
||||
};
|
||||
cb.equal(root.get(JpaAction_.active), true));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byDistributionSetId(final Long distributionSetId) {
|
||||
@@ -158,4 +152,4 @@ public final class ActionSpecifications {
|
||||
criteriaBuilder.equal(actionRoot.get(JpaAction_.target).get(JpaTarget_.id), targetId));
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -967,38 +967,29 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Long actionId = createTargetAndAssignDs();
|
||||
|
||||
// test and verify
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING));
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING,
|
||||
Action.Status.RUNNING, true);
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING));
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, Action.Status.RUNNING, true);
|
||||
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.ERROR));
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR,
|
||||
Action.Status.ERROR, false);
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.ERROR));
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
|
||||
|
||||
// try with disabled late feedback
|
||||
repositoryProperties.setRejectActionStatusForClosedAction(true);
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
|
||||
|
||||
// test
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR,
|
||||
Action.Status.ERROR, false);
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
|
||||
|
||||
// try with enabled late feedback - should not make a difference as it
|
||||
// only allows intermediate feedback and not multiple close
|
||||
repositoryProperties.setRejectActionStatusForClosedAction(false);
|
||||
controllerManagement
|
||||
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
|
||||
|
||||
// test
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR,
|
||||
Action.Status.ERROR, false);
|
||||
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
|
||||
|
||||
assertThat(actionStatusRepository.count()).isEqualTo(3);
|
||||
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(3);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1716,27 +1707,24 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
actionStatus, true);
|
||||
}
|
||||
|
||||
private void assertActionStatus(final Long actionId, final String controllerId,
|
||||
private void assertActionStatus(
|
||||
final Long actionId, final String controllerId,
|
||||
final TargetUpdateStatus expectedTargetUpdateStatus, final Action.Status expectedActionActionStatus,
|
||||
final Action.Status expectedActionStatus, final boolean actionActive) {
|
||||
final TargetUpdateStatus targetStatus = targetManagement.getByControllerID(controllerId).get()
|
||||
.getUpdateStatus();
|
||||
final TargetUpdateStatus targetStatus = targetManagement.getByControllerID(controllerId).get().getUpdateStatus();
|
||||
assertThat(targetStatus).isEqualTo(expectedTargetUpdateStatus);
|
||||
final Action action = deploymentManagement.findAction(actionId).get();
|
||||
assertThat(action.getStatus()).isEqualTo(expectedActionActionStatus);
|
||||
assertThat(action.isActive()).isEqualTo(actionActive);
|
||||
final List<ActionStatus> actionStatusList = controllerManagement.findActionStatusByAction(PAGE, actionId)
|
||||
.getContent();
|
||||
final List<ActionStatus> actionStatusList = controllerManagement.findActionStatusByAction(PAGE, actionId).getContent();
|
||||
assertThat(actionStatusList.get(actionStatusList.size() - 1).getStatus()).isEqualTo(expectedActionStatus);
|
||||
if (actionActive) {
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(controllerId).get().getId())
|
||||
.isEqualTo(actionId);
|
||||
assertThat(controllerManagement.findActiveActionWithHighestWeight(controllerId).get().getId()).isEqualTo(actionId);
|
||||
}
|
||||
}
|
||||
|
||||
private void createTargetType(String targetTypeName) {
|
||||
systemSecurityContext.runAsSystem(() ->
|
||||
targetTypeManagement.create(entityFactory.targetType().create().name(targetTypeName)));
|
||||
systemSecurityContext.runAsSystem(() -> targetTypeManagement.create(entityFactory.targetType().create().name(targetTypeName)));
|
||||
}
|
||||
|
||||
@Step
|
||||
|
||||
Reference in New Issue
Block a user