diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java index 15dbfe884..5f082142d 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/exception/SpServerError.java @@ -138,6 +138,12 @@ public enum SpServerError { SP_ARTIFACT_LOAD_FAILED("hawkbit.server.error.artifact.loadFailed", "Load of artifact failed with internal server error."), + /** + * + */ + SP_ARTIFACT_BINARY_DELETED("hawkbit.server.error.artifact.binaryDeleted", + "The artifact binary does not exist anymore."), + /** * */ diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactBinaryNoLongerExistsException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactBinaryNoLongerExistsException.java new file mode 100644 index 000000000..b18d28326 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/ArtifactBinaryNoLongerExistsException.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.exception; + +import org.eclipse.hawkbit.exception.AbstractServerRtException; +import org.eclipse.hawkbit.exception.SpServerError; +import org.eclipse.hawkbit.repository.model.SoftwareModule; + +/** + * Exception indicating that an artifact's binary does not exist anymore. This + * might be caused due to the soft deletion of a {@link SoftwareModule}. + * + */ +public class ArtifactBinaryNoLongerExistsException extends AbstractServerRtException { + private static final SpServerError THIS_ERROR = SpServerError.SP_ARTIFACT_BINARY_DELETED; + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new ArtifactBinaryGoneException error. + */ + public ArtifactBinaryNoLongerExistsException() { + super(THIS_ERROR); + } + + /** + * Creates a new ArtifactBinaryGoneException error with cause. + * + * @param cause + * for the exception + */ + public ArtifactBinaryNoLongerExistsException(final Throwable cause) { + super(THIS_ERROR, cause); + } + + /** + * Creates a new ArtifactBinaryGoneException error with message. + * + * @param message + * of the error + */ + public ArtifactBinaryNoLongerExistsException(final String message) { + super(message, THIS_ERROR); + } + +} diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java index 9d7ef4f6c..869149d3d 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java @@ -16,6 +16,7 @@ import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact; import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadArtifactRestApi; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.SoftwareModuleManagement; +import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNoLongerExistsException; import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Artifact; @@ -63,6 +64,9 @@ public class MgmtDownloadArtifactResource implements MgmtDownloadArtifactRestApi final SoftwareModule module = softwareModuleManagement.get(softwareModuleId) .orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId)); + if (module.isDeleted()) { + throw new ArtifactBinaryNoLongerExistsException(); + } final Artifact artifact = module.getArtifact(artifactId) .orElseThrow(() -> new EntityNotFoundException(Artifact.class, artifactId)); diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java index 43c7bf8a9..a9bb366ff 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResource.java @@ -117,11 +117,12 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi { @SuppressWarnings("squid:S3655") public ResponseEntity getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId, @PathVariable("artifactId") final Long artifactId) { - final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId); final MgmtArtifact reponse = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).get()); - MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), reponse); + if (!module.isDeleted()) { + MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), reponse); + } return ResponseEntity.ok(reponse); } 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 62b1d69d9..268005e37 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 @@ -50,6 +50,7 @@ import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; +import org.hamcrest.Matchers; import org.json.JSONArray; import org.json.JSONObject; import org.junit.jupiter.api.BeforeEach; @@ -391,8 +392,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra // upload mvc.perform(multipart("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(jsonPath("$.hashes.md5", equalTo(md5sum))) .andExpect(jsonPath("$.hashes.sha1", equalTo(sha1sum))) .andExpect(jsonPath("$.hashes.sha256", equalTo(sha256sum))) @@ -435,8 +435,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra final SoftwareModule sm = testdataFactory.createSoftwareModuleOs("sm" + i); mvc.perform(multipart("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(jsonPath("$.hashes.md5", equalTo(md5sum))) .andExpect(jsonPath("$.hashes.sha1", equalTo(sha1sum))) .andExpect(jsonPath("$.hashes.sha256", equalTo(sha256sum))) @@ -518,6 +517,31 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra "http://localhost/rest/v1/softwaremodules/" + sm.getId() + "/artifacts/" + artifact.getId()))); } + @Test + @Description("Verifies the listing of an artifact that belongs to a soft deleted software module.") + public void getArtifactSoftDeleted() throws Exception { + // prepare data for test + final SoftwareModule sm = testdataFactory.createSoftwareModuleOs("softDeleted"); + final Artifact artifact = testdataFactory.createArtifacts(sm.getId()).get(0); + testdataFactory.createDistributionSet(Arrays.asList(sm)); + softwareModuleManagement.delete(sm.getId()); + + // perform test + mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts/{artId}", sm.getId(), artifact.getId()) + .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.id", equalTo(artifact.getId().intValue()))) + .andExpect(jsonPath("$.size", equalTo((int) artifact.getSize()))) + .andExpect(jsonPath("$.hashes.md5", equalTo(artifact.getMd5Hash()))) + .andExpect(jsonPath("$.hashes.sha1", equalTo(artifact.getSha1Hash()))) + .andExpect(jsonPath("$.hashes.sha256", equalTo(artifact.getSha256Hash()))) + .andExpect(jsonPath("$.providedFilename", equalTo(artifact.getFilename()))) + .andExpect(jsonPath("$._links", Matchers.not(Matchers.hasKey("download")))) + .andExpect(jsonPath("$._links.self.href", + equalTo(String.format("http://localhost/rest/v1/softwaremodules/%d/artifacts/%d", sm.getId(), + artifact.getId())))); + } + @Test @Description("Verifies the listing of all artifacts assigned to a software module. That includes the artifact metadata and download links.") public void getArtifacts() throws Exception { @@ -562,6 +586,11 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra final SoftwareModule sm = testdataFactory.createSoftwareModuleOs(); + final SoftwareModule smSoftDeleted = testdataFactory.createSoftwareModuleOs("softDeleted"); + final Artifact artifactSoftDeleted = testdataFactory.createArtifacts(smSoftDeleted.getId()).get(0); + testdataFactory.createDistributionSet(Arrays.asList(smSoftDeleted)); + softwareModuleManagement.delete(smSoftDeleted.getId()); + // no artifact available mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts/1234567/download", sm.getId())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); @@ -588,6 +617,10 @@ public class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegra mvc.perform(delete("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId())).andDo(MockMvcResultPrinter.print()) .andExpect(status().isMethodNotAllowed()); + + // SM soft deleted + mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts/{artifactId}/download", smSoftDeleted.getId(), + artifactSoftDeleted.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isGone()); } @Test diff --git a/hawkbit-rest/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java b/hawkbit-rest/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java index d1c5f3f04..283c7f59a 100644 --- a/hawkbit-rest/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java +++ b/hawkbit-rest/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/exception/ResponseExceptionHandler.java @@ -61,6 +61,7 @@ public class ResponseExceptionHandler { ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_UPLOAD_FAILED_SHA256_MATCH, HttpStatus.BAD_REQUEST); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_UPLOAD_FAILED_MD5_MATCH, HttpStatus.BAD_REQUEST); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_DELETE_FAILED, HttpStatus.INTERNAL_SERVER_ERROR); + ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_BINARY_DELETED, HttpStatus.GONE); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ARTIFACT_LOAD_FAILED, HttpStatus.INTERNAL_SERVER_ERROR); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_QUOTA_EXCEEDED, HttpStatus.FORBIDDEN); ERROR_TO_HTTP_STATUS.put(SpServerError.SP_FILE_SIZE_QUOTA_EXCEEDED, HttpStatus.FORBIDDEN); diff --git a/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/softwaremodules-api-guide.adoc b/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/softwaremodules-api-guide.adoc index 565e3f99f..d2ba5b382 100644 --- a/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/softwaremodules-api-guide.adoc +++ b/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/softwaremodules-api-guide.adoc @@ -483,6 +483,9 @@ include::../errors/403.adoc[] | See <> include::../errors/405.adoc[] include::../errors/406.adoc[] +| `410 Gone` +| The resource does not exist anymore. The software module might be soft deleted. +| include::../errors/429.adoc[] |===