diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 359be202cf..8e2d480c51 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -632,22 +632,6 @@ Slice findByFilterOrderByLinkedDistributionSet(@NotNull Pageable pageabl @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Page findByRsqlAndTag(@NotNull Pageable pageable, @NotNull String rsqlParam, long tagId); - /** - * Toggles {@link TargetTag} assignment to given {@link Target}s by means that - * if some (or all) of the targets in the list have the {@link Tag} not yet - * assigned, they will be. Only if all of them have the tag already assigned - * they will be removed instead. - * - * @deprecated since 0.6.0 - not very usable with very unclear logic - * @param controllerIds to toggle for - * @param tagName to toggle - * @return TagAssigmentResult with all metadata of the assignment outcome. - * @throws EntityNotFoundException if tag with given name does not exist - */ - @Deprecated - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection controllerIds, @NotEmpty String tagName); - /** * Initiates {@link TargetType} assignment to given {@link Target}s. If some * targets in the list have the {@link TargetType} not yet assigned, they will @@ -705,19 +689,6 @@ Slice findByFilterOrderByLinkedDistributionSet(@NotNull Pageable pageabl @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) List unassignTag(@NotEmpty List controllerIds, long targetTagId); - /** - * Un-assign a {@link TargetTag} assignment to given {@link Target}. - * - * @deprecated since 0.6.0 - use {@link #unassignTag(List, long)} instead - * @param controllerId to un-assign for - * @param targetTagId to un-assign - * @return the unassigned target or if no target is unassigned - * @throws EntityNotFoundException if TAG with given ID does not exist - */ - @Deprecated(forRemoval = true) - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - Target unassignTag(@NotEmpty String controllerId, long targetTagId); - /** * Un-assign a {@link TargetType} assignment to given {@link Target}. * @@ -991,4 +962,33 @@ Page findMetaDataByControllerIdAndRsql(@NotNull Pageable pageabl */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) TargetMetadata updateMetadata(@NotEmpty String controllerId, @NotNull MetaData metadata); -} + + /** + * Toggles {@link TargetTag} assignment to given {@link Target}s by means that + * if some (or all) of the targets in the list have the {@link Tag} not yet + * assigned, they will be. Only if all of them have the tag already assigned + * they will be removed instead. + * + * @deprecated since 0.6.0 - not very usable with very unclear logic + * @param controllerIds to toggle for + * @param tagName to toggle + * @return TagAssigmentResult with all metadata of the assignment outcome. + * @throws EntityNotFoundException if tag with given name does not exist + */ + @Deprecated + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection controllerIds, @NotEmpty String tagName); + + /** + * Un-assign a {@link TargetTag} assignment to given {@link Target}. + * + * @deprecated since 0.6.0 - use {@link #unassignTag(List, long)} instead + * @param controllerId to un-assign for + * @param targetTagId to un-assign + * @return the unassigned target or if no target is unassigned + * @throws EntityNotFoundException if TAG with given ID does not exist + */ + @Deprecated(forRemoval = true) + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) + Target unassignTag(@NotEmpty String controllerId, long targetTagId); +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java index d715dd4014..306eaaf96f 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java @@ -34,12 +34,11 @@ /** * Management service for {@link TargetTag}s. - * */ public interface TargetTagManagement { /** - * count {@link TargetTag}s. + * Count {@link TargetTag}s. * * @return size of {@link TargetTag}s */ @@ -49,32 +48,21 @@ public interface TargetTagManagement { /** * Creates a new {@link TargetTag}. * - * @param create - * to be created - * + * @param create to be created * @return the new created {@link TargetTag} - * - * @throws EntityAlreadyExistsException - * if given object already exists - * @throws ConstraintViolationException - * if fields are not filled as specified. Check - * {@link TagCreate} for field constraints. + * @throws EntityAlreadyExistsException if given object already exists + * @throws ConstraintViolationException if fields are not filled as specified. Check {@link TagCreate} for field constraints. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) TargetTag create(@NotNull @Valid TagCreate create); /** - * created multiple {@link TargetTag}s. + * Created multiple {@link TargetTag}s. * - * @param creates - * to be created + * @param creates to be created * @return the new created {@link TargetTag}s - * - * @throws EntityAlreadyExistsException - * if given object has already an ID. - * @throws ConstraintViolationException - * if fields are not filled as specified. Check - * {@link TagCreate} for field constraints. + * @throws EntityAlreadyExistsException if given object has already an ID. + * @throws ConstraintViolationException if fields are not filled as specified. Check {@link TagCreate} for field constraints. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET) List create(@NotNull @Valid Collection creates); @@ -82,11 +70,8 @@ public interface TargetTagManagement { /** * Deletes {@link TargetTag} with given name. * - * @param targetTagName - * tag name of the {@link TargetTag} to be deleted - * - * @throws EntityNotFoundException - * if tag with given name does not exist + * @param targetTagName tag name of the {@link TargetTag} to be deleted + * @throws EntityNotFoundException if tag with given name does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET) void delete(@NotEmpty String targetTagName); @@ -94,9 +79,7 @@ public interface TargetTagManagement { /** * returns all {@link TargetTag}s. * - * @param pageable - * page parameter - * + * @param pageable page parameter * @return all {@link TargetTag}s */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) @@ -105,18 +88,12 @@ public interface TargetTagManagement { /** * Retrieves all target tags based on the given specification. * - * @param pageable - * pagination parameter - * @param rsqlParam - * rsql query string - * + * @param pageable pagination parameter + * @param rsqlParam rsql query string * @return the found {@link Target}s, never {@code null} - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the + * @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 + * @throws RSQLParameterSyntaxException if the RSQL syntax is wrong */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Page findByRsql(@NotNull Pageable pageable, @NotNull String rsqlParam); @@ -124,8 +101,7 @@ public interface TargetTagManagement { /** * Find {@link TargetTag} based on given Name. * - * @param name - * to look for. + * @param name to look for. * @return {@link TargetTag} */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) @@ -134,8 +110,7 @@ public interface TargetTagManagement { /** * Finds {@link TargetTag} by given id. * - * @param id - * to search for + * @param id to search for * @return the found {@link TargetTag} */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) @@ -144,28 +119,21 @@ public interface TargetTagManagement { /** * Finds {@link TargetTag} by given ids. * - * @param ids - * the ids to for + * @param ids the ids to for * @return the found {@link TargetTag}s */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) List get(@NotEmpty Collection ids); /** - * updates the {@link TargetTag}. + * Updates the {@link TargetTag}. * - * @param update - * the {@link TargetTag} with updated values + * @param update the {@link TargetTag} with updated values * @return the updated {@link TargetTag} * - * @throws EntityNotFoundException - * in case the {@link TargetTag} does not exists and cannot be - * updated - * @throws ConstraintViolationException - * if fields are not filled as specified. Check - * {@link TagUpdate} for field constraints. + * @throws EntityNotFoundException in case the {@link TargetTag} does not exist and cannot be updated + * @throws ConstraintViolationException if fields are not filled as specified. Check {@link TagUpdate} for field constraints. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) TargetTag update(@NotNull @Valid TagUpdate update); - -} +} \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java index 9cf5804971..cdf12e8c0b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaTargetManagement.java @@ -478,43 +478,6 @@ private static boolean hasNoTypeFilterActive(final FilterParams filterParams) { return Boolean.TRUE.equals(filterParams.getSelectTargetWithNoTargetType()); } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public TargetTagAssignmentResult toggleTagAssignment(final Collection controllerIds, final String tagName) { - final TargetTag tag = targetTagRepository - .findByNameEquals(tagName) - .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagName)); - final List allTargets = targetRepository - .findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds)); - if (allTargets.size() < controllerIds.size()) { - throw new EntityNotFoundException(Target.class, controllerIds, - allTargets.stream().map(Target::getControllerId).toList()); - } - - final List alreadyAssignedTargets = targetRepository.findAll( - TargetSpecifications.hasTagName(tagName).and(TargetSpecifications.hasControllerIdIn(controllerIds))); - - // all are already assigned -> unassign - if (alreadyAssignedTargets.size() == allTargets.size()) { - - alreadyAssignedTargets.forEach(target -> target.removeTag(tag)); - return new TargetTagAssignmentResult(0, Collections.emptyList(), - Collections.unmodifiableList(alreadyAssignedTargets), tag); - } - - allTargets.removeAll(alreadyAssignedTargets); - // some or none are assigned -> assign - allTargets.forEach(target -> target.addTag(tag)); - final TargetTagAssignmentResult result = new TargetTagAssignmentResult(alreadyAssignedTargets.size(), - targetRepository.saveAll(allTargets), Collections.emptyList(), tag); - - // no reason to persist the tag - entityManager.detach(tag); - return result; - } - @Override @Transactional @Retryable(include = { @@ -619,25 +582,6 @@ public List unassignTag(final List controllerIds, final long tar return result; } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target unassignTag(final String controllerId, final long targetTagId) { - final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId); - - final TargetTag tag = targetTagRepository.findById(targetTagId) - .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId)); - - target.removeTag(tag); - - final Target result = targetRepository.save(target); - - // No reason to save the tag - entityManager.detach(tag); - return result; - } - @Override @Transactional @Retryable(include = { @@ -974,4 +918,60 @@ public Page findByControllerAttributesRequested(final Pageable pageReq) return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageReq, List.of(TargetSpecifications.hasRequestControllerAttributesTrue())); } + + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public TargetTagAssignmentResult toggleTagAssignment(final Collection controllerIds, final String tagName) { + final TargetTag tag = targetTagRepository + .findByNameEquals(tagName) + .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagName)); + final List allTargets = targetRepository + .findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds)); + if (allTargets.size() < controllerIds.size()) { + throw new EntityNotFoundException(Target.class, controllerIds, + allTargets.stream().map(Target::getControllerId).toList()); + } + + final List alreadyAssignedTargets = targetRepository.findAll( + TargetSpecifications.hasTagName(tagName).and(TargetSpecifications.hasControllerIdIn(controllerIds))); + + // all are already assigned -> unassign + if (alreadyAssignedTargets.size() == allTargets.size()) { + + alreadyAssignedTargets.forEach(target -> target.removeTag(tag)); + return new TargetTagAssignmentResult(0, Collections.emptyList(), + Collections.unmodifiableList(alreadyAssignedTargets), tag); + } + + allTargets.removeAll(alreadyAssignedTargets); + // some or none are assigned -> assign + allTargets.forEach(target -> target.addTag(tag)); + final TargetTagAssignmentResult result = new TargetTagAssignmentResult(alreadyAssignedTargets.size(), + targetRepository.saveAll(allTargets), Collections.emptyList(), tag); + + // no reason to persist the tag + entityManager.detach(tag); + return result; + } + + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Target unassignTag(final String controllerId, final long targetTagId) { + final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId); + + final TargetTag tag = targetTagRepository.findById(targetTagId) + .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId)); + + target.removeTag(tag); + + final Target result = targetRepository.save(target); + + // No reason to save the tag + entityManager.detach(tag); + return result; + } } diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java index 4b567e3d41..23890b79be 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java @@ -286,42 +286,6 @@ Query fields based on the Feed Item Query Language (FIQL). See Entity Definition available fields.""") String rsqlParam); - /** - * Handles the POST request to toggle the assignment of targets by the given - * tag id. - * - * @deprecated since 0.6.0 - not very usable with very unclear logic - * @param targetTagId - * the ID of the target tag to retrieve - * @param assignedTargetRequestBodies - * list of controller ids to be toggled - * @return the list of assigned targets and unassigned targets. - */ - @Operation(summary = "Toggles target tag assignment", description = "Handles the POST request of toggle target " + - "assignment. The request body must always be a list of controller ids.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved"), - @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication."), - @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + - "changed (i.e. read-only) or data volume restriction applies."), - @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), - @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json."), - @ApiResponse(responseCode = "409", description = "E.g. in case an entity is created or modified by another " + - "user in another request at the same time. You may retry your modification request."), - @ApiResponse(responseCode = "415", description = "The request was attempt with a media-type which is not " + - "supported by the server for this resource."), - @ApiResponse(responseCode = "429", description = "Too many requests. The server will refuse further attempts and the client has to wait another second.") - }) - @PostMapping(value = MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING - + MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING + "/toggleTagAssignment", consumes = { - MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { - MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) - @Deprecated(forRemoval = true) - ResponseEntity toggleTagAssignment(@PathVariable("targetTagId") Long targetTagId, - List assignedTargetRequestBodies); - /** * Handles the PUT request to assign targets to the given tag id. * @@ -447,6 +411,42 @@ ResponseEntity unassignTargets( @Schema(description = "List of controller ids to be unassigned", example = "[\"controllerId1\", \"controllerId2\"]") @RequestBody List controllerId); + /** + * Handles the POST request to toggle the assignment of targets by the given + * tag id. + * + * @deprecated since 0.6.0 - not very usable with very unclear logic + * @param targetTagId + * the ID of the target tag to retrieve + * @param assignedTargetRequestBodies + * list of controller ids to be toggled + * @return the list of assigned targets and unassigned targets. + */ + @Operation(summary = "[DEPRECATED] Toggles target tag assignment", description = "Handles the POST request of toggle target " + + "assignment. The request body must always be a list of controller ids.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully retrieved"), + @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), + @ApiResponse(responseCode = "401", description = "The request requires user authentication."), + @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + + "changed (i.e. read-only) or data volume restriction applies."), + @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), + @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json."), + @ApiResponse(responseCode = "409", description = "E.g. in case an entity is created or modified by another " + + "user in another request at the same time. You may retry your modification request."), + @ApiResponse(responseCode = "415", description = "The request was attempt with a media-type which is not " + + "supported by the server for this resource."), + @ApiResponse(responseCode = "429", description = "Too many requests. The server will refuse further attempts and the client has to wait another second.") + }) + @PostMapping(value = MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + + MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING + "/toggleTagAssignment", consumes = { + MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { + MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) + @Deprecated(forRemoval = true) + ResponseEntity toggleTagAssignment(@PathVariable("targetTagId") Long targetTagId, + List assignedTargetRequestBodies); + /** * Handles the POST request to assign targets to the given tag id. * @@ -455,7 +455,7 @@ ResponseEntity unassignTargets( * @param assignedTargetRequestBodies list of controller ids to be assigned * @return the list of assigned targets. */ - @Operation(summary = "Assign target(s) to given tagId and return targets", + @Operation(summary = "[DEPRECATED] Assign target(s) to given tagId and return targets", description = "Handles the POST request of target assignment. Already assigned target will be ignored.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully assigned"),