Abstract RepositoryManagement test (#2631)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-08-28 12:56:16 +03:00
parent 42b0bc06a9
commit 4f0a8893c7
52 changed files with 1901 additions and 3042 deletions

View File

@@ -239,11 +239,10 @@ public interface ControllerManagement {
*
* @param actionId to the handle status for
* @param message for the status
* @return the update action in case the status has been changed to {@link Status#RETRIEVED}
* @throws EntityNotFoundException if action with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Action registerRetrieved(long actionId, String message);
void registerRetrieved(long actionId, String message);
/**
* Updates attributes of the controller according to the given {@link UpdateMode}.
@@ -260,8 +259,7 @@ public interface ControllerManagement {
Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map<String, String> attributes, UpdateMode mode);
/**
* Finds {@link Target} based on given controller ID returns found Target without details, i.e.
* NO {@link Target#getTags()} and {@link Target#getActions()} possible.
* Finds {@link Target} based on given controller ID returns found Target without details
*
* @param controllerId to look for.
* @return {@link Target} or {@code null} if it does not exist
@@ -271,9 +269,7 @@ public interface ControllerManagement {
Optional<Target> findByControllerId(@NotEmpty String controllerId);
/**
* Finds {@link Target} based on given ID returns found Target without details, i.e.
* NO {@link Target#getTags()} and {@link Target#getActions()}
* possible.
* Finds {@link Target} based on given ID returns found Target without details
*
* @param targetId to look for.
* @return {@link Target} or {@code null} if it does not exist

View File

@@ -242,16 +242,6 @@ public interface DeploymentManagement extends PermissionSupport {
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
Page<ActionStatus> findActionStatusByAction(long actionId, @NotNull Pageable pageable);
/**
* Counts all the {@link ActionStatus} entries of the given {@link Action}.
*
* @param actionId to be filtered on
* @return count of {@link ActionStatus} entries
* @throws EntityNotFoundException if action with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
long countActionStatusByAction(long actionId);
/**
* Retrieves all messages for an {@link ActionStatus}.<p/>
* No entity based access control applied.

View File

@@ -13,7 +13,6 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
import org.springframework.security.access.prepost.PreAuthorize;
/**

View File

@@ -9,9 +9,6 @@
*/
package org.eclipse.hawkbit.repository;
import java.util.Optional;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -20,17 +17,9 @@ import lombok.Getter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* Management service for {@link DistributionSetTag}s.

View File

@@ -88,11 +88,9 @@ public final class MaintenanceScheduleHelper {
if (allNotEmpty(cronSchedule, duration, timezone)) {
validateCronSchedule(cronSchedule);
validateDuration(duration);
// check if there is a window currently active or available in
// future.
if (!getNextMaintenanceWindow(cronSchedule, duration, timezone).isPresent()) {
throw new InvalidMaintenanceScheduleException(
"No valid maintenance window available after current time");
// check if there is a window currently active or available in the future.
if (getNextMaintenanceWindow(cronSchedule, duration, timezone).isEmpty()) {
throw new InvalidMaintenanceScheduleException("No valid maintenance window available after current time");
}
} else if (atLeastOneNotEmpty(cronSchedule, duration, timezone)) {
throw new InvalidMaintenanceScheduleException("All of schedule, duration and timezone should either be null or non empty.");

View File

@@ -18,11 +18,9 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
/**
* An implementation of the {@link PageRequest} which is offset based by means
* the offset is given and not the page number as in the original
* {@link PageRequest} implementation where the offset is generated. Due that
* the REST-API is working with {@code offset} and {@code limit} parameter we
* need an offset based page request.
* An implementation of the {@link PageRequest} which is offset based by means the offset is given and not the page number as in the original
* {@link PageRequest} implementation where the offset is generated. Due to the REST-API is working with {@code offset} and {@code limit}
* parameter we need an offset based page request.
*/
@Getter
@EqualsAndHashCode(callSuper = true)

View File

@@ -20,8 +20,7 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
public interface QuotaManagement {
/**
* @return maximum number of {@link ActionStatus} entries that the
* controller can report for an {@link Action}.
* @return maximum number of {@link ActionStatus} entries that the controller can report for an {@link Action}.
*/
int getMaxStatusEntriesPerAction();
@@ -31,15 +30,12 @@ public interface QuotaManagement {
int getMaxAttributeEntriesPerTarget();
/**
* @return maximum number of allowed {@link RolloutGroup}s per
* {@link Rollout}.
* @return maximum number of allowed {@link RolloutGroup}s per {@link Rollout}.
*/
int getMaxRolloutGroupsPerRollout();
/**
* @return maximum number of
* {@link ControllerManagement#getActionHistoryMessages(Long, int)}
* for an individual {@link ActionStatus}.
* @return maximum number of action (history) messages per actions status.
*/
int getMaxMessagesPerActionStatus();
@@ -49,7 +45,7 @@ public interface QuotaManagement {
int getMaxMetaDataEntriesPerSoftwareModule();
/**
* @return maximum number of meta data entries per distribution set
* @return maximum number of metadata entries per distribution set
*/
int getMaxMetaDataEntriesPerDistributionSet();
@@ -80,14 +76,12 @@ public interface QuotaManagement {
int getMaxTargetsPerRolloutGroup();
/**
* @return the maximum number of target distribution set assignments
* resulting from a manual assignment
* @return the maximum number of target distribution set assignments resulting from a manual assignment
*/
int getMaxTargetDistributionSetAssignmentsPerManualAssignment();
/**
* @return the maximum number of targets for an automatic distribution set
* assignment
* @return the maximum number of targets for an automatic distribution set assignment
*/
int getMaxTargetsPerAutoAssignment();
@@ -110,5 +104,4 @@ public interface QuotaManagement {
* @return the maximum number of distribution set types per target type
*/
int getMaxDistributionSetTypesPerTargetType();
}
}

View File

@@ -1,68 +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;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Collection of regular expression characters to check strings
*/
public class RegexCharacterCollection {
private final EnumSet<RegexChar> characters;
private final Pattern findAnyCharacter;
public RegexCharacterCollection(final RegexChar... characters) {
this.characters = EnumSet.copyOf(Arrays.asList(characters));
this.findAnyCharacter = getPatternFindAnyCharacter();
}
public static boolean stringContainsCharacter(final String stringToCheck,
final RegexCharacterCollection regexCharacterCollection) {
return regexCharacterCollection.findAnyCharacter.matcher(stringToCheck).matches();
}
private Pattern getPatternFindAnyCharacter() {
final String regexCharacters = characters.stream().map(RegexChar::getRegExp)
.collect(Collectors.joining());
final String regularExpression = String.format(".*[%s]+.*", regexCharacters);
return Pattern.compile(regularExpression);
}
public enum RegexChar {
WHITESPACE("\\s", "character.whitespace"), DIGITS("0-9", "character.digits"), QUOTATION_MARKS("'\"",
"character.quotationMarks"), SLASHES("\\/\\\\", "character.slashes"), GREATER_THAN(
">"), LESS_THAN("<"), EQUALS_SYMBOL("="), EXCLAMATION_MARK("!"), QUESTION_MARK("?"), COLON(":");
private final String regExp;
private final String l18nReferenceDescription;
RegexChar(final String character) {
this(character, null);
}
RegexChar(final String regExp, final String l18nReferenceDescription) {
this.regExp = regExp;
this.l18nReferenceDescription = l18nReferenceDescription;
}
public String getRegExp() {
return regExp;
}
public Optional<String> getL18nReferenceDescription() {
return Optional.ofNullable(l18nReferenceDescription);
}
}
}

View File

@@ -12,7 +12,6 @@ package org.eclipse.hawkbit.repository;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -23,15 +22,12 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
public final class RepositoryConstants {
/**
* Prefix that the server puts in front of
* {@link ActionStatus#getMessages()} if the message is generated by the
* server.
* Prefix that the server puts in front of action status messages if the message is generated by the server.
*/
public static final String SERVER_MESSAGE_PREFIX = "Update Server: ";
/**
* Number of {@link DistributionSetType}s that are generated as part of
* default tenant setup.
* Number of {@link DistributionSetType}s that are generated as part of default tenant setup.
*/
public static final int DEFAULT_DS_TYPES_IN_TENANT = 3;
@@ -41,8 +37,7 @@ public final class RepositoryConstants {
public static final int MAX_ACTION_COUNT = 100;
/**
* Maximum number of messages that can be retrieved by a controller for an
* {@link Action}.
* Maximum number of messages that can be retrieved by a controller for an {@link Action}.
*/
public static final int MAX_ACTION_HISTORY_MSG_COUNT = 100;

View File

@@ -10,8 +10,9 @@
package org.eclipse.hawkbit.repository;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -22,32 +23,25 @@ import org.springframework.security.access.prepost.PreAuthorize;
public interface RolloutExecutor {
/**
* This execution should only be triggered by the system as a background job and
* not available via API.
*
* This execution should only be triggered by the system as a background job and not available via API.
* <p/>
* Process rollout based on its current {@link Rollout#getStatus()}.
*
* For {@link RolloutStatus#CREATING} that means creating the
* {@link RolloutGroup}s with {@link Target}s and when finished switch to
* {@link RolloutStatus#READY}.
*
* For {@link RolloutStatus#READY} that means switching to
* {@link RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is set and
* time of calling this method is beyond this point in time. This auto start
* mechanism is optional. Call {@link #start(Long)} otherwise.
*
* For {@link RolloutStatus#STARTING} that means starting the first
* {@link RolloutGroup}s in line and when finished switch to
* <p/>
* For {@link RolloutStatus#CREATING} that means creating the {@link org.eclipse.hawkbit.repository.model.RolloutGroup}s
* with {@link Target}s and when finished switch to {@link RolloutStatus#READY}.
* <p/>
* For {@link RolloutStatus#READY} that means switching to {@link RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is set and
* time of calling this method is beyond this point in time. This auto start mechanism is optional.
* Call {@link RolloutManagement#start(long)} otherwise.
* <p/>
* For {@link RolloutStatus#STARTING} that means starting the first {@link RolloutGroup}s in line and when finished switch to
* {@link RolloutStatus#RUNNING}.
*
* For {@link RolloutStatus#RUNNING} that means checking to activate further
* groups based on the defined thresholds. Switched to
* <p/>
* For {@link RolloutStatus#RUNNING} that means checking to activate further groups based on the defined thresholds. Switched to
* {@link RolloutStatus#FINISHED} is all groups are finished.
*
* For {@link RolloutStatus#DELETING} that means either soft delete in case
* rollout was already {@link RolloutStatus#RUNNING} which results in status
* change {@link RolloutStatus#DELETED} or hard delete from the persistence
* otherwise.
* <p/>
* For {@link RolloutStatus#DELETING} that means either soft delete in case rollout was already {@link RolloutStatus#RUNNING}
* which results in status change {@link RolloutStatus#DELETED} or hard delete from the persistence otherwise.
*/
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
void execute(Rollout rollout);

View File

@@ -95,15 +95,6 @@ public interface RolloutGroupManagement extends PermissionSupport {
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
Page<RolloutGroup> findByRollout(long rolloutId, @NotNull Pageable pageable);
/**
* Retrieves a page of {@link RolloutGroup}s filtered by a given {@link Rollout}.
*
* @param rolloutId the ID of the rollout to filter the {@link RolloutGroup}s
* @return a page of found {@link RolloutGroup}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
long countByRollout(long rolloutId);
/**
* Get targets of specified rollout group.
*

View File

@@ -24,27 +24,22 @@ public interface RolloutHandler {
/**
* Process rollout based on its current {@link Rollout#getStatus()}.
*
* For {@link Rollout.RolloutStatus#CREATING} that means creating the
* {@link RolloutGroup}s with {@link Target}s and when finished switch to
* <p/>
* For {@link Rollout.RolloutStatus#CREATING} that means creating the {@link RolloutGroup}s with {@link Target}s and when finished switch to
* {@link Rollout.RolloutStatus#READY}.
*
* For {@link Rollout.RolloutStatus#READY} that means switching to
* {@link Rollout.RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is
* set and time of calling this method is beyond this point in time. This auto
* <p/>
* For {@link Rollout.RolloutStatus#READY} that means switching to {@link Rollout.RolloutStatus#STARTING} if the
* {@link Rollout#getStartAt()} is set and time of calling this method is beyond this point in time. This auto
* start mechanism is optional. Call {@link RolloutManagement#start(long)} otherwise.
*
* For {@link Rollout.RolloutStatus#STARTING} that means starting the first
* {@link RolloutGroup}s in line and when finished switch to
* <p/>
* For {@link Rollout.RolloutStatus#STARTING} that means starting the first {@link RolloutGroup}s in line and when finished switch to
* {@link Rollout.RolloutStatus#RUNNING}.
*
* For {@link Rollout.RolloutStatus#RUNNING} that means checking to activate
* further groups based on the defined thresholds. Switched to
* <p/>
* For {@link Rollout.RolloutStatus#RUNNING} that means checking to activate further groups based on the defined thresholds. Switched to
* {@link Rollout.RolloutStatus#FINISHED} is all groups are finished.
*
* For {@link Rollout.RolloutStatus#DELETING} that means either soft delete in
* case rollout was already {@link Rollout.RolloutStatus#RUNNING} which results
* in status change {@link Rollout.RolloutStatus#DELETED} or hard delete from
* <p/>
* For {@link Rollout.RolloutStatus#DELETING} that means either soft delete in case rollout was already
* {@link Rollout.RolloutStatus#RUNNING} which results in status change {@link Rollout.RolloutStatus#DELETED} or hard delete from
* the persistence otherwise.
*/
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)

View File

@@ -86,25 +86,19 @@ public interface RolloutManagement extends PermissionSupport {
long countByDistributionSetIdAndRolloutIsStoppable(long setId);
/**
* Persists a new rollout entity. The filter within the
* {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets which
* are effected by this rollout to create. The amount of groups will be defined
* as equally sized.
*
* The rollout is not started. Only the preparation of the rollout is done,
* creating and persisting all the necessary groups. The Rollout and the groups
* are persisted in {@link RolloutStatus#CREATING} and
* {@link RolloutGroupStatus#CREATING}.
*
* The RolloutScheduler will start to assign targets to the groups. Once all
* targets have been assigned to the groups, the rollout status is changed to
* {@link RolloutStatus#READY} so it can be started with .
* Persists a new rollout entity. The filter within the {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets which
* are effected by this rollout to create. The amount of groups will be defined as equally sized.
* <p/>
* The rollout is not started. Only the preparation of the rollout is done, creating and persisting all the necessary groups. The Rollout
* and the groups are persisted in {@link RolloutStatus#CREATING} and {@link RolloutGroupStatus#CREATING}.
* <p/>
* The RolloutScheduler will start to assign targets to the groups. Once all targets have been assigned to the groups, the rollout status
* is changed to {@link RolloutStatus#READY} so it can be started with .
*
* @param create the rollout entity to create
* @param amountGroup the amount of groups to split the rollout into
* @param confirmationRequired if a confirmation is required by the device group(s) of the rollout
* @param conditions the rolloutgroup conditions and actions which should be applied
* for each {@link RolloutGroup}
* @param conditions the rolloutgroup conditions and actions which should be applied for each {@link RolloutGroup}
* @param dynamicRolloutGroupTemplate the template for dynamic rollout groups
* @return the persisted rollout.
* @throws EntityNotFoundException if given {@link DistributionSet} does not exist
@@ -118,61 +112,45 @@ public interface RolloutManagement extends PermissionSupport {
@NotNull RolloutGroupConditions conditions, DynamicRolloutGroupTemplate dynamicRolloutGroupTemplate);
/**
* Persists a new rollout entity. The filter within the
* {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets which
* are effected by this rollout to create. The amount of groups will be defined
* as equally sized.
*
* The rollout is not started. Only the preparation of the rollout is done,
* creating and persisting all the necessary groups. The Rollout and the groups
* are persisted in {@link RolloutStatus#CREATING} and
* {@link RolloutGroupStatus#CREATING}.
*
* The RolloutScheduler will start to assign targets to the groups. Once all
* targets have been assigned to the groups, the rollout status is changed to
* {@link RolloutStatus#READY} so it can be started with .
* Persists a new rollout entity. The filter within the {@link Rollout#getTargetFilterQuery()} is used to retrieve the targets which
* are effected by this rollout to create. The amount of groups will be defined as equally sized.
* <p/>
* The rollout is not started. Only the preparation of the rollout is done, creating and persisting all the necessary groups. The Rollout
* and the groups are persisted in {@link RolloutStatus#CREATING} and {@link RolloutGroupStatus#CREATING}.
* <p/>
* The RolloutScheduler will start to assign targets to the groups. Once all targets have been assigned to the groups, the rollout status is
* changed to {@link RolloutStatus#READY} so it can be started with .
*
* @param create the rollout entity to create
* @param amountGroup the amount of groups to split the rollout into
* @param confirmationRequired if a confirmation is required by the device group(s) of the rollout
* @param conditions the rolloutgroup conditions and actions which should be applied
* for each {@link RolloutGroup}
* @param conditions the rolloutgroup conditions and actions which should be applied for each {@link RolloutGroup}
* @return the persisted rollout.
* @throws EntityNotFoundException if given {@link DistributionSet} does not exist
* @throws ConstraintViolationException if rollout or group parameters are invalid.
* @throws AssignmentQuotaExceededException if the maximum number of allowed targets per rollout group is
* exceeded.
* @throws AssignmentQuotaExceededException if the maximum number of allowed targets per rollout group is exceeded.
*/
@PreAuthorize(SpringEvalExpressions.HAS_CREATE_REPOSITORY)
Rollout create(@NotNull @Valid Create create, int amountGroup, boolean confirmationRequired,
@NotNull RolloutGroupConditions conditions);
Rollout create(@NotNull @Valid Create create, int amountGroup, boolean confirmationRequired, @NotNull RolloutGroupConditions conditions);
/**
* Persists a new rollout entity. The filter within the
* {@link Rollout#getTargetFilterQuery()} is used to filter the targets which
* are affected by this rollout. The given groups will be used to create the
* groups.
*
* The rollout is not started. Only the preparation of the rollout is done,
* creating and persisting all the necessary groups. The Rollout and the groups
* are persisted in {@link RolloutStatus#CREATING} and
* {@link RolloutGroupStatus#CREATING}.
*
* The RolloutScheduler will start to assign targets to the groups. Once all
* targets have been assigned to the groups, the rollout status is changed to
* {@link RolloutStatus#READY} so it can be started with
* {@link #start(long)}.
* Persists a new rollout entity. The filter within the {@link Rollout#getTargetFilterQuery()} is used to filter the targets which
* are affected by this rollout. The given groups will be used to create the groups.
* <p/>
* The rollout is not started. Only the preparation of the rollout is done, creating and persisting all the necessary groups. The Rollout
* and the groups are persisted in {@link RolloutStatus#CREATING} and {@link RolloutGroupStatus#CREATING}.
* <p/>
* The RolloutScheduler will start to assign targets to the groups. Once all targets have been assigned to the groups, the rollout status is
* changed to {@link RolloutStatus#READY} so it can be started with {@link #start(long)}.
*
* @param rollout the rollout entity to create
* @param groups optional definition of groups
* @param conditions the rollout group conditions and actions which should be applied
* for each {@link RolloutGroup} if not defined by the RolloutGroup
* itself
* @param conditions the rollout group conditions and actions which should be applied for each {@link RolloutGroup} if not defined by the
* RolloutGroup itself
* @return the persisted rollout.
* @throws EntityNotFoundException if given {@link DistributionSet} does not exist
* @throws ConstraintViolationException if rollout or group parameters are invalid
* @throws AssignmentQuotaExceededException if the maximum number of allowed targets per rollout group is
* exceeded.
* @throws AssignmentQuotaExceededException if the maximum number of allowed targets per rollout group is exceeded.
*/
@PreAuthorize(SpringEvalExpressions.HAS_CREATE_REPOSITORY)
Rollout create(@Valid @NotNull Create rollout, @NotNull @Valid List<GroupCreate> groups, RolloutGroupConditions conditions);
@@ -192,8 +170,7 @@ public interface RolloutManagement extends PermissionSupport {
*
* @param deleted flag if deleted rollouts should be included
* @param pageable the page request to sort and limit the result
* @return a list of rollouts with details of targets count for different
* statuses
* @return a list of rollouts with details of targets count for different statuses
*/
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
Page<Rollout> findAllWithDetailedStatus(boolean deleted, @NotNull Pageable pageable);
@@ -218,7 +195,7 @@ public interface RolloutManagement extends PermissionSupport {
* @param rsql search text which matches name or description of rollout
* @param deleted flag if deleted rollouts should be included
* @param pageable the page request to sort and limit the result
* @return the founded rollout or {@code null} if rollout with given ID does not exists
* @return the founded rollout or {@code null} if rollout with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
Page<Rollout> findByRsqlWithDetailedStatus(@NotEmpty String rsql, boolean deleted, @NotNull Pageable pageable);
@@ -356,6 +333,7 @@ public interface RolloutManagement extends PermissionSupport {
/**
* Stop a rollout
*
* @param rolloutId of the rollout to be stopped
* @return stopped rollout
*/

View File

@@ -11,10 +11,7 @@ package org.eclipse.hawkbit.repository;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -25,8 +22,6 @@ import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.NamedEntity;
@@ -36,7 +31,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule.MetadataValue;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.security.access.prepost.PreAuthorize;
/**
@@ -90,6 +84,7 @@ public interface SoftwareModuleManagement<T extends SoftwareModule>
@ToString(callSuper = true)
final class Create extends UpdateCreate {
private SoftwareModuleType type;
private boolean encrypted;
}
@@ -123,6 +118,5 @@ public interface SoftwareModuleManagement<T extends SoftwareModule>
@ValidString
@Size(max = SoftwareModule.VENDOR_MAX_SIZE)
private String vendor;
private SoftwareModuleType type;
}
}

View File

@@ -115,7 +115,4 @@ public interface SystemManagement {
*/
@PreAuthorize("hasAuthority('UPDATE_" + SpPermission.TENANT_CONFIGURATION + "')")
TenantMetaData updateTenantMetadata(long defaultDsType);
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
TenantMetaData getTenantMetadata(long tenantId);
}

View File

@@ -56,13 +56,12 @@ public interface TargetFilterQueryManagement<T extends TargetFilterQuery>
* Verifies the provided filter syntax.
*
* @param query to verify
* @return <code>true</code> if syntax is valid
* @throws RSQLParameterUnsupportedFieldException if a field in the RSQL string is used but not provided by the
* given {@code fieldNameProvider}
* @throws RSQLParameterSyntaxException if the RSQL syntax is wrong
*/
@PreAuthorize(SpringEvalExpressions.HAS_READ_REPOSITORY)
boolean verifyTargetFilterQuerySyntax(@NotNull String query);
void verifyTargetFilterQuerySyntax(@NotNull String query);
/**
* Counts all target filters that have a given auto assign distribution set

View File

@@ -60,7 +60,6 @@ public interface TargetManagement<T extends Target>
String HAS_READ_TARGET_AND_READ_ROLLOUT = HAS_READ_REPOSITORY + " and hasAuthority('READ_" + SpPermission.ROLLOUT + "')";
String HAS_READ_TARGET_AND_READ_DISTRIBUTION_SET = HAS_READ_REPOSITORY + " and hasAuthority('READ_" + SpPermission.DISTRIBUTION_SET + "')";
String DETAILS_BASE = "base";
String DETAILS_AUTO_CONFIRMATION_STATUS = "autoConfirmationStatus";
String DETAILS_TAGS = "tags";
@@ -111,11 +110,6 @@ public interface TargetManagement<T extends Target>
@PreAuthorize(HAS_READ_REPOSITORY)
Target getWithDetails(@NotEmpty String controllerId, String detailsKey);
@PreAuthorize(HAS_READ_REPOSITORY)
default Target getWithDetails(@NotEmpty String controllerId) {
return getWithDetails(controllerId, DETAILS_BASE);
}
@PreAuthorize(HAS_READ_REPOSITORY)
default Target getWithAutoConfigurationStatus(@NotEmpty String controllerId) {
return getWithDetails(controllerId, DETAILS_AUTO_CONFIRMATION_STATUS);

View File

@@ -59,8 +59,7 @@ public interface TenantConfigurationManagement extends PermissionSupport {
<T extends Serializable> Map<String, TenantConfigurationValue<T>> addOrUpdateConfiguration(Map<String, T> configurations);
/**
* Deletes a specific configuration for the current tenant. Does nothing in
* case there is no tenant specific configuration value.
* Deletes a specific configuration for the current tenant. Does nothing in case there is no tenant specific configuration value.
*
* @param configurationKey the configuration key to be deleted
*/
@@ -68,59 +67,46 @@ public interface TenantConfigurationManagement extends PermissionSupport {
void deleteConfiguration(String configurationKey);
/**
* Retrieves a configuration value from the e.g. tenant overwritten
* configuration values or in case the tenant does not a have a specific
* Retrieves a configuration value from the e.g. tenant overwritten configuration values or in case the tenant does not a have a specific
* configuration the global default value hold in the {@link Environment}.
*
* @param configurationKeyName the key of the configuration
* @return the converted configuration value either from the tenant specific
* configuration stored or from the fall back default values or
* {@code null} in case key has not been configured and not default
* value exists
* @return the converted configuration value either from the tenant specific configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default value exists
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not
* match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given
* {@code propertyType}
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String configurationKeyName);
/**
* Retrieves a configuration value from the e.g. tenant overwritten
* configuration values or in case the tenant does not a have a specific
* Retrieves a configuration value from the e.g. tenant overwritten configuration values or in case the tenant does not a have a specific
* configuration the global default value hold in the {@link Environment}.
*
* @param <T> the type of the configuration value
* @param configurationKeyName the key of the configuration
* @param propertyType the type of the configuration value, e.g. {@code String.class}
* , {@code Integer.class}, etc
* @return the converted configuration value either from the tenant specific
* configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default
* value exists
* @param propertyType the type of the configuration value, e.g. {@code String.class}, {@code Integer.class}, etc
* @return the converted configuration value either from the tenant specific configuration stored or from the fallback default values or
* {@code null} in case key has not been configured and not default value exists
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in general does not
* match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given
* {@code propertyType}
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String configurationKeyName,
Class<T> propertyType);
/**
* returns the global configuration property either defined in the property
* file or an default value otherwise.
* returns the global configuration property either defined in the property file or a default value otherwise.
*
* @param <T> the type of the configuration value
* @param configurationKeyName the key of the configuration
* @param propertyType the type of the configuration value, e.g. {@code String.class}
* , {@code Integer.class}, etc
* @param propertyType the type of the configuration value, e.g. {@code String.class}, {@code Integer.class}, etc
* @return the global configured value
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in the property
* file or the default value does not match the expected type
* and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given
* {@code propertyType}
* @throws TenantConfigurationValidatorException if the {@code propertyType} and the value in the property file or the default value
* does not match the expected type and format defined by the Key
* @throws ConversionFailedException if the property cannot be converted to the given {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_READ_REPOSITORY)
<T> T getGlobalConfigurationValue(String configurationKeyName, Class<T> propertyType);

View File

@@ -25,7 +25,8 @@ public interface TenantStatsManagement {
*
* @return collected statistics
*/
@PreAuthorize("hasAuthority('" + SpRole.TENANT_ADMIN + "')" + " or " +
@PreAuthorize(
"hasAuthority('" + SpRole.TENANT_ADMIN + "')" + " or " +
SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN + " or " +
SpringEvalExpressions.IS_SYSTEM_CODE)
TenantUsage getStatsOfTenant();

View File

@@ -13,8 +13,7 @@ import java.util.Arrays;
import java.util.Optional;
/**
* Enumerates the supported update modes. Each mode represents an attribute
* update strategy.
* Enumerates the supported update modes. Each mode represents an attribute update strategy.
*
* @see ControllerManagement
*/
@@ -34,9 +33,4 @@ public enum UpdateMode {
* Removal update strategy
*/
REMOVE;
public static Optional<UpdateMode> valueOfIgnoreCase(final String name) {
return Arrays.stream(values()).filter(mode -> mode.name().equalsIgnoreCase(name)).findAny();
}
}
}

View File

@@ -46,7 +46,7 @@ public class ValidStringValidator implements ConstraintValidator<ValidString, St
try {
return cleaner.isValid(stringToDocument(value));
} catch (final Exception ex) {
log.error(String.format("There was an exception during bean field value (%s) validation", value), ex);
log.error("There was an exception during bean field value ({}) validation", value, ex);
return false;
}
}

View File

@@ -1,31 +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.model;
import java.util.Collection;
import lombok.Builder;
import lombok.Data;
/**
* Holds distribution set filter parameters.
*/
@Data
@Builder
public final class DistributionSetFilter {
private final Boolean isDeleted;
private final Boolean isComplete;
private final Boolean isValid;
private final Long typeId;
private final String searchText;
private final Boolean selectDSWithNoTag;
private final Collection<String> tagNames;
}

View File

@@ -14,9 +14,8 @@ import java.time.LocalDateTime;
import lombok.Data;
/**
* The poll time object which holds all the necessary information around the
* target poll time, e.g. the last poll time, the next poll time and the overdue
* poll time.
* The poll time object which holds all the necessary information around the target poll time, e.g. the last poll time, the next poll time and
* the overdue poll time.
*/
@Data
public class PollStatus {
@@ -26,7 +25,8 @@ public class PollStatus {
private final LocalDateTime overdueDate;
private final LocalDateTime currentDate;
public PollStatus(final LocalDateTime lastPollDate, final LocalDateTime nextPollDate,
public PollStatus(
final LocalDateTime lastPollDate, final LocalDateTime nextPollDate,
final LocalDateTime overdueDate, final LocalDateTime currentDate) {
this.lastPollDate = lastPollDate;
this.nextPollDate = nextPollDate;
@@ -35,11 +35,9 @@ public class PollStatus {
}
/**
* calculates if the target poll time is overdue and the target has not been
* polled in the configured poll time interval.
* Calculates if the target poll time is overdue and the target has not been polled in the configured poll time interval.
*
* @return {@code true} if the current time is after the poll time overdue
* date otherwise {@code false}.
* @return {@code true} if the current time is after the poll time overdue date otherwise {@code false}.
*/
public boolean isOverdue() {
return currentDate.isAfter(overdueDate);

View File

@@ -1,111 +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;
import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar;
import org.junit.jupiter.api.Test;
/**
* Feature: Unit Tests - Repository<br/>
* Story: Regular expression helper
*/
class RegexCharTest {
private static final int INDEX_FIRST_PRINTABLE_ASCII_CHAR = 32;
private static final int INDEX_LAST_PRINTABLE_ASCII_CHAR = 127;
private static final String TEST_STRING = getPrintableAsciiCharacters();
/**
* Verifies every RegexChar can be used to exclusively find the desired characters in a String.
*/
@Test
void allRegexCharsOnlyFindExpectedChars() {
for (final RegexChar character : RegexChar.values()) {
switch (character) {
case DIGITS:
assertRegexCharExclusivelyFindsGivenCharacters(character, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
break;
case WHITESPACE:
assertRegexCharExclusivelyFindsGivenCharacters(character, " ", "\t");
break;
case SLASHES:
assertRegexCharExclusivelyFindsGivenCharacters(character, "/", "\\");
break;
case QUOTATION_MARKS:
assertRegexCharExclusivelyFindsGivenCharacters(character, "\"", "'");
break;
default:
assertRegexCharExclusivelyFindsGivenCharacters(character, character.getRegExp());
break;
}
}
}
/**
* Verifies that combinations of RegexChars can be used to find the desired characters in a String.
*/
@Test
void combinedRegexCharsFindExpectedChars() {
final RegexCharacterCollection greaterAndLessThan = new RegexCharacterCollection(RegexChar.GREATER_THAN,
RegexChar.LESS_THAN);
final RegexCharacterCollection equalsAndQuestionMark = new RegexCharacterCollection(RegexChar.EQUALS_SYMBOL,
RegexChar.QUESTION_MARK);
final RegexCharacterCollection colonAndWhitespace = new RegexCharacterCollection(RegexChar.COLON,
RegexChar.WHITESPACE);
assertRegexCharsExclusivelyFindsGivenCharacters(greaterAndLessThan, "<", ">");
assertRegexCharsExclusivelyFindsGivenCharacters(equalsAndQuestionMark, "=", "?");
assertRegexCharsExclusivelyFindsGivenCharacters(colonAndWhitespace, ":", " ", "\t");
}
private static String getPrintableAsciiCharacters() {
final StringBuilder stringBuilder = new StringBuilder();
for (int i = INDEX_FIRST_PRINTABLE_ASCII_CHAR; i < INDEX_LAST_PRINTABLE_ASCII_CHAR; i++) {
stringBuilder.append((char) i);
}
stringBuilder.append("\t");
return stringBuilder.toString();
}
private static String insertStringIntoString(final String baseString, final String stringToInsert,
final int position) {
final StringBuilder stringBuilder = new StringBuilder(baseString);
return stringBuilder.insert(position, stringToInsert).toString();
}
private void assertRegexCharExclusivelyFindsGivenCharacters(final RegexChar characterToVerify,
final String... charactersExpectedToBeFoundByRegex) {
assertRegexCharsExclusivelyFindsGivenCharacters(new RegexCharacterCollection(characterToVerify),
charactersExpectedToBeFoundByRegex);
}
private void assertRegexCharsExclusivelyFindsGivenCharacters(final RegexCharacterCollection regexToVerify,
final String... charactersExpectedToBeFoundByRegex) {
String notMatchingString = TEST_STRING;
for (final String character : charactersExpectedToBeFoundByRegex) {
notMatchingString = notMatchingString.replace(character, "");
}
for (final String character : charactersExpectedToBeFoundByRegex) {
assertThat(RegexCharacterCollection.stringContainsCharacter("", regexToVerify)).isFalse();
assertThat(RegexCharacterCollection.stringContainsCharacter(notMatchingString, regexToVerify)).isFalse();
assertThat(RegexCharacterCollection.stringContainsCharacter(character, regexToVerify)).isTrue();
assertThat(RegexCharacterCollection
.stringContainsCharacter(insertStringIntoString(notMatchingString, character, 0), regexToVerify))
.isTrue();
assertThat(RegexCharacterCollection.stringContainsCharacter(
insertStringIntoString(notMatchingString, character, notMatchingString.length()), regexToVerify)).isTrue();
assertThat(RegexCharacterCollection.stringContainsCharacter(
insertStringIntoString(notMatchingString, character, notMatchingString.length() / 2), regexToVerify)).isTrue();
}
}
}