diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java index 38c74d6e1..e7f36b206 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericDistributionSetUpdate.java @@ -10,12 +10,20 @@ package org.eclipse.hawkbit.repository.builder; import jakarta.annotation.Nullable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.Accessors; import java.util.Optional; /** * Update implementation. */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@Accessors(fluent = true) public class GenericDistributionSetUpdate extends AbstractDistributionSetUpdateCreate implements DistributionSetUpdate { @@ -25,17 +33,4 @@ public class GenericDistributionSetUpdate extends AbstractDistributionSetUpdateC public GenericDistributionSetUpdate(final Long id) { super.id = id; } - - public DistributionSetUpdate locked(@Nullable final Boolean locked) { - if (Boolean.FALSE.equals(locked)) { - this.locked = null; - } else { - this.locked = locked; - } - return this; - } - - public Boolean getLocked() { - return locked; - } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java index 26fc60a40..9bf995e04 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/GenericSoftwareModuleUpdate.java @@ -10,12 +10,20 @@ package org.eclipse.hawkbit.repository.builder; import jakarta.annotation.Nullable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.Accessors; import java.util.Optional; /** * Update implementation. */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@Accessors(fluent = true) public class GenericSoftwareModuleUpdate extends AbstractSoftwareModuleUpdateCreate implements SoftwareModuleUpdate { @@ -25,17 +33,4 @@ public class GenericSoftwareModuleUpdate extends AbstractSoftwareModuleUpdateCre public GenericSoftwareModuleUpdate(final Long id) { super.id = id; } - - public SoftwareModuleUpdate locked(@Nullable final Boolean locked) { - if (Boolean.FALSE.equals(locked)) { - this.locked = null; - } else { - this.locked = locked; - } - return this; - } - - public Boolean getLocked() { - return locked; - } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java index eaab8dfd2..d02d82a6b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java @@ -286,8 +286,11 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { update.getDescription().ifPresent(set::setDescription); update.getVersion().ifPresent(set::setVersion); - if (Boolean.TRUE.equals(update.getLocked()) && !set.isLocked()) { + // lock/unlock ONLY if locked flag is present! + if (Boolean.TRUE.equals(update.locked())) { set.lock(); + } else if (Boolean.FALSE.equals(update.locked())) { + set.unlock(); } if (update.isRequiredMigrationStep() != null diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java index b67dc897b..d62e1843a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaSoftwareModuleManagement.java @@ -142,8 +142,12 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement { update.getDescription().ifPresent(module::setDescription); update.getVendor().ifPresent(module::setVendor); - if (Boolean.TRUE.equals(update.getLocked()) && !module.isLocked()) { + + // lock/unlock ONLY if locked flag is present! + if (Boolean.TRUE.equals(update.locked())) { module.lock(); + } else if (Boolean.FALSE.equals(update.locked())) { + module.unlock(); } return softwareModuleRepository.save(module); diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java index 2d2b4817c..9a7524a8d 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/distributionset/MgmtDistributionSetRequestBodyPut.java @@ -39,8 +39,11 @@ public class MgmtDistributionSetRequestBodyPut { private String version; @JsonProperty - @Schema(description = "Put it to true only if want to lock the distribution set. Otherwise skip it. " + - "Shall not be false!", + @Schema(description = """ + Should be set only if change of locked state is requested. If put, the distribution set locked flag will be + set to the requested. Note: unlock (i.e. set this property to false) with extreme care! + In general once distribution set is locked it shall not be unlocked. Note that it could have been assigned / + deployed to targets.""", example = "true") private Boolean locked; diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java index fabd6c898..50a0b77cb 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/json/model/softwaremodule/MgmtSoftwareModuleRequestBodyPut.java @@ -30,8 +30,11 @@ public class MgmtSoftwareModuleRequestBodyPut { private String vendor; @JsonProperty - @Schema(description = "Put it to true only if want to lock the software module. Otherwise skip it. " + - "Shall not be false!", + @Schema(description = """ + Should be set only if change of locked state is requested. If put, the software module locked flag will be + set to the requested. Note: unlock (i.e. set this property to false) with extreme care! + In general once software module is locked it shall not be unlocked. Note that it could have been assigned / + deployed to targets.""", example = "true") private Boolean locked; } \ No newline at end of file diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java index d0f670619..05d48d9df 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetMapper.java @@ -46,44 +46,35 @@ public final class MgmtDistributionSetMapper { /** * {@link MgmtDistributionSetRequestBodyPost}s to {@link DistributionSet}s. * - * @param sets - * to convert + * @param sets to convert * @return converted list of {@link DistributionSet}s */ static List dsFromRequest(final Collection sets, final EntityFactory entityFactory) { - return sets.stream().map(dsRest -> fromRequest(dsRest, entityFactory)).collect(Collectors.toList()); } /** * {@link MgmtDistributionSetRequestBodyPost} to {@link DistributionSet}. * - * @param dsRest - * to convert + * @param dsRest to convert * @return converted {@link DistributionSet} */ private static DistributionSetCreate fromRequest(final MgmtDistributionSetRequestBodyPost dsRest, final EntityFactory entityFactory) { - final List modules = new ArrayList<>(); - if (dsRest.getOs() != null) { modules.add(dsRest.getOs().getId()); } - if (dsRest.getApplication() != null) { modules.add(dsRest.getApplication().getId()); } - if (dsRest.getRuntime() != null) { modules.add(dsRest.getRuntime().getId()); } - if (dsRest.getModules() != null) { dsRest.getModules().forEach(module -> modules.add(module.getId())); } - return entityFactory.distributionSet().create().name(dsRest.getName()).version(dsRest.getVersion()) .description(dsRest.getDescription()).type(dsRest.getType()).modules(modules) .requiredMigrationStep(dsRest.getRequiredMigrationStep()); @@ -103,6 +94,7 @@ public final class MgmtDistributionSetMapper { if (distributionSet == null) { return null; } + final MgmtDistributionSet response = new MgmtDistributionSet(); MgmtRestModelMapper.mapNamedToNamed(response, distributionSet); @@ -180,7 +172,6 @@ public final class MgmtDistributionSetMapper { } static List toResponseDsMetadata(final List metadata) { - final List mappedList = new ArrayList<>(metadata.size()); for (final DistributionSetMetadata distributionSetMetadata : metadata) { mappedList.add(toResponseDsMetadata(distributionSetMetadata)); @@ -195,4 +186,4 @@ public final class MgmtDistributionSetMapper { return sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList()); } -} +} \ No newline at end of file diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java index 7c67a3157..5a110e9ab 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleMapper.java @@ -17,6 +17,8 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.eclipse.hawkbit.api.ApiType; import org.eclipse.hawkbit.api.ArtifactUrl; import org.eclipse.hawkbit.api.ArtifactUrlHandler; @@ -42,12 +44,9 @@ import org.springframework.hateoas.Link; /** * A mapper which maps repository model to RESTful model representation and * back. - * */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class MgmtSoftwareModuleMapper { - private MgmtSoftwareModuleMapper() { - // Utility class - } private static SoftwareModuleCreate fromRequest(final EntityFactory entityFactory, final MgmtSoftwareModuleRequestBodyPost smsRest) { @@ -157,7 +156,6 @@ public final class MgmtSoftwareModuleMapper { } static void addLinks(final Artifact artifact, final MgmtArtifact response) { - response.add(linkTo(methodOn(MgmtDownloadArtifactResource.class) .downloadArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withRel("download") .expand()); @@ -165,7 +163,6 @@ public final class MgmtSoftwareModuleMapper { static void addLinks(final Artifact artifact, final MgmtArtifact response, final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement) { - final List urls = artifactUrlHandler.getUrls( new URLPlaceholder(systemManagement.getTenantMetadata().getTenant(), systemManagement.getTenantMetadata().getId(), null, null, @@ -173,5 +170,4 @@ public final class MgmtSoftwareModuleMapper { artifact.getId(), artifact.getSha1Hash())), ApiType.MGMT, null); urls.forEach(entry -> response.add(Link.of(entry.getRef()).withRel(entry.getRel()).expand())); } - -} +} \ No newline at end of file diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java index c2187eb08..302d502cd 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java @@ -1071,8 +1071,8 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr assertThat(distributionSetManagement.count()).isEqualTo(1); assertThat(set.isLocked()).as("Created distribution set should not be locked").isFalse(); + // lock final String body = new JSONObject().put("locked", true).toString(); - mvc.perform(put("/rest/v1/distributionsets/{dsId}", set.getId()).content(body) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) @@ -1084,8 +1084,8 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr } @Test - @Description("Tests the unlock. It is verified that the distribution set can't be unmarked as locked through update operation.") - void unlockDistributionSetSkippedSilently() throws Exception { + @Description("Tests the unlock.") + void unlockDistributionSet() throws Exception { // prepare test data assertThat(distributionSetManagement.findByCompleted(PAGE, true)).hasSize(0); @@ -1094,19 +1094,19 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr distributionSetManagement.lock(set.getId()); assertThat(distributionSetManagement.get(set.getId()) .orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, set.getId())).isLocked()) - .as("Created software module should not be locked") + .as("Distribution set should be locked") .isTrue(); + // unlock final String body = new JSONObject().put("locked", false).toString(); - mvc.perform(put("/rest/v1/distributionsets/{dsId}", set.getId()).content(body) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()) - .andExpect(jsonPath("$.locked", equalTo(true))); + .andExpect(jsonPath("$.locked", equalTo(false))); final DistributionSet updatedSet = distributionSetManagement.get(set.getId()).get(); - assertThat(updatedSet.isLocked()).isEqualTo(true); + assertThat(updatedSet.isLocked()).isEqualTo(false); } @Test diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java index f1018976b..45bb29b12 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java @@ -202,6 +202,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes .pollInterval(10L, TimeUnit.MILLISECONDS) .until(() -> sm.getLastModifiedAt() > 0L && sm.getLastModifiedBy() != null); + // lock final String body = new JSONObject().put("locked", true).toString(); final ResultActions resultActions = mvc.perform(put("/rest/v1/softwaremodules/{smId}", sm.getId()).content(body) @@ -221,15 +222,15 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes } @Test - @Description("Tests the unlock. It is verified that the software module can't be unmarked as locked through update operation.") + @Description("Tests the unlock.") @WithUser(principal = "smUpdateTester", allSpPermissions = true) - void unlockSoftwareModuleSkippedSilently() throws Exception { + void unlockSoftwareModule() throws Exception { final SoftwareModule sm = softwareModuleManagement.create( entityFactory.softwareModule().create().type(osType).name("name1").version("version1")); softwareModuleManagement.lock(sm.getId()); assertThat(softwareModuleManagement.get(sm.getId()) .orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, sm.getId())).isLocked()) - .as("Created software module should not be locked") + .as("Software module is locked") .isTrue(); // ensures that we are not to fast so that last modified is not set correctly Awaitility.await() @@ -237,6 +238,7 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes .pollInterval(10L, TimeUnit.MILLISECONDS) .until(() -> sm.getLastModifiedAt() > 0L && sm.getLastModifiedBy() != null); + // unlock final String body = new JSONObject().put("locked", false).toString(); final ResultActions resultActions = mvc.perform(put("/rest/v1/softwaremodules/{smId}", sm.getId()).content(body) @@ -244,14 +246,14 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes final SoftwareModule updatedSm = softwareModuleManagement.get(sm.getId()).get(); assertThat(updatedSm.getLastModifiedBy()).isEqualTo("smUpdateTester"); - assertThat(updatedSm.isLocked()).isTrue(); // not unlocked + assertThat(updatedSm.isLocked()).isFalse(); // not unlocked resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$.id", equalTo(sm.getId().intValue()))) .andExpect(jsonPath("$.lastModifiedBy", equalTo("smUpdateTester"))) .andExpect(jsonPath("$.lastModifiedAt", equalTo(updatedSm.getLastModifiedAt()))) - .andExpect(jsonPath("$.locked", equalTo(true))); + .andExpect(jsonPath("$.locked", equalTo(false))); } @Test