diff options
author | andre.schmid <andre.schmid@est.tech> | 2021-05-14 20:38:45 +0100 |
---|---|---|
committer | Christophe Closset <christophe.closset@intl.att.com> | 2021-06-14 08:16:08 +0000 |
commit | c82aebcde26e34c4151531b4d7a8f6e7689734ba (patch) | |
tree | fe14e6fadded7f43f9e1634b89d1fb9358b44253 /catalog-be/src/main/java | |
parent | ab6a90df6444ef7282fe9de8fe8107641bf7082f (diff) |
Add models imports endpoint and persistence structure
Create the structure to persist the model imports.
Changed create model API, allowing to create a model along its TOSCA
descriptor import structure.
Introduced an endpoint to update the imports of a model.
Change-Id: Ic775ef544051c29c721cacc20b37c2fb20338be9
Issue-ID: SDC-3614
Signed-off-by: André Schmid <andre.schmid@est.tech>
Diffstat (limited to 'catalog-be/src/main/java')
3 files changed, 120 insertions, 19 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java index 1ef4cef701..7f68a00a8b 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java @@ -18,17 +18,25 @@ */ package org.openecomp.sdc.be.components.impl; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Optional; +import org.apache.commons.lang3.StringUtils; import org.openecomp.sdc.be.model.Model; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier; import org.openecomp.sdc.be.model.operations.impl.ModelOperation; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - @Component("modelBusinessLogic") public class ModelBusinessLogic { - private static final Logger log = LoggerFactory.getLogger(ModelBusinessLogic.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ModelBusinessLogic.class); private final ModelOperation modelOperation; @Autowired @@ -37,7 +45,56 @@ public class ModelBusinessLogic { } public Model createModel(final Model model) { - log.debug("createModel: creating model {}", model); + LOGGER.debug("createModel: creating model {}", model); return modelOperation.createModel(model, false); } + + public Optional<Model> findModel(final String modelName) { + if (StringUtils.isEmpty(modelName)) { + return Optional.empty(); + } + return modelOperation.findModelByName(modelName); + } + + public void createModelImports(final String modelName, final InputStream modelImportsZip) { + if (StringUtils.isEmpty(modelName)) { + throw ModelOperationExceptionSupplier.invalidModel(modelName).get(); + } + if (modelImportsZip == null) { + throw ModelOperationExceptionSupplier.emptyModelImports().get(); + } + if (findModel(modelName).isEmpty()) { + throw ModelOperationExceptionSupplier.invalidModel(modelName).get(); + } + + final var fileBytes = readBytes(modelImportsZip); + final Map<String, byte[]> zipFilesPathContentMap = unzipInMemory(fileBytes); + if (zipFilesPathContentMap.isEmpty()) { + throw ModelOperationExceptionSupplier.emptyModelImports().get(); + } + + modelOperation.createModelImports(modelName, zipFilesPathContentMap); + } + + private Map<String, byte[]> unzipInMemory(final byte[] fileBytes) { + try { + return ZipUtils.readZip(fileBytes, false); + } catch (final ZipException e) { + throw ModelOperationExceptionSupplier.couldNotReadImports().get(); + } + } + + private byte[] readBytes(final InputStream modelImportsZip) { + try (final InputStream in = modelImportsZip; final ByteArrayOutputStream os = new ByteArrayOutputStream()) { + final var buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + return os.toByteArray(); + } catch (final IOException e) { + LOGGER.debug("Could not read the model imports zip", e); + throw ModelOperationExceptionSupplier.couldNotReadImports().get(); + } + } }
\ No newline at end of file diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java index f4fc883b4c..0c5e4aebd6 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java @@ -28,6 +28,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.servers.Server; import io.swagger.v3.oas.annotations.tags.Tag; +import java.io.InputStream; import java.util.Arrays; import javax.inject.Inject; import javax.validation.Valid; @@ -35,10 +36,13 @@ import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.glassfish.jersey.media.multipart.FormDataParam; import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; import org.openecomp.sdc.be.components.impl.ModelBusinessLogic; import org.openecomp.sdc.be.components.impl.ResourceImportManager; @@ -55,10 +59,10 @@ import org.openecomp.sdc.be.ui.model.ModelCreateRequest; import org.openecomp.sdc.be.user.Role; import org.openecomp.sdc.be.user.UserBusinessLogic; import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.util.ValidationUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestBody; /** * Root resource (exposed at "/" path) @@ -85,34 +89,67 @@ public class ModelServlet extends AbstractValidationsServlet { @POST @Path("/model") - @Consumes(MediaType.APPLICATION_JSON) + @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) - @Operation(description = "Create model", method = "POST", summary = "Returns created model", responses = { + @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + @Operation(description = "Create a TOSCA model, along with its imports files", method = "POST", summary = "Create a TOSCA model", responses = { @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))), @ApiResponse(responseCode = "201", description = "Model created"), - @ApiResponse(responseCode = "403", description = "Restricted operation"), @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"), - @ApiResponse(responseCode = "409", description = "Resource already exists")}) - @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "409", description = "Model already exists")}) public Response createModel(@Parameter(description = "model to be created", required = true) - @Valid @RequestBody @NotNull final ModelCreateRequest modelCreateRequest, - @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { - - validateUser(userId); + @NotNull @Valid @FormDataParam("model") final ModelCreateRequest modelCreateRequest, + @Parameter(description = "the model TOSCA imports zipped", required = true) + @NotNull @FormDataParam("modelImportsZip") final InputStream modelImportsZip, + @HeaderParam(value = Constants.USER_ID_HEADER) final String userId) { + validateUser(ValidationUtils.sanitizeInputString(userId)); + final var modelName = ValidationUtils.sanitizeInputString(modelCreateRequest.getName().trim()); try { - final Model modelCreateResponse = modelBusinessLogic + final Model createdModel = modelBusinessLogic .createModel(new JMapper<>(Model.class, ModelCreateRequest.class).getDestination(modelCreateRequest)); + modelBusinessLogic.createModelImports(modelName, modelImportsZip); return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), - RepresentationUtils.toRepresentation(modelCreateResponse)); + RepresentationUtils.toRepresentation(createdModel)); + } catch (final BusinessException e) { + throw e; + } catch (final Exception e) { + var errorMsg = String.format("Unexpected error while creating model '%s' imports", modelName); + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(errorMsg); + log.error(errorMsg, e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + @PUT + @Path("/model/imports") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + @Operation(description = "Update a model TOSCA imports", method = "PUT", summary = "Update a model TOSCA imports", responses = { + @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))), + @ApiResponse(responseCode = "204", description = "Model imports updated"), + @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"), + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "404", description = "Model not found")}) + public Response updateModelImports(@Parameter(description = "model to be created", required = true) + @NotNull @FormDataParam("modelName") String modelName, + @Parameter(description = "the model TOSCA imports zipped", required = true) + @NotNull @FormDataParam("modelImportsZip") final InputStream modelImportsZip, + @HeaderParam(value = Constants.USER_ID_HEADER) final String userId) { + validateUser(ValidationUtils.sanitizeInputString(userId)); + modelName = ValidationUtils.sanitizeInputString(modelName); + try { + modelBusinessLogic.createModelImports(modelName, modelImportsZip); } catch (final BusinessException e) { throw e; } catch (final Exception e) { - var errorMsg = String - .format("Unexpected error while creating model '%s'", modelCreateRequest.getName()); + var errorMsg = String.format("Unexpected error while creating model '%s' imports", modelName); BeEcompErrorManager.getInstance().logBeRestApiGeneralError(errorMsg); log.error(errorMsg, e); return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); } + return Response.status(Status.NO_CONTENT).build(); } private void validateUser(final String userId) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java index 7c25f8aef8..062e03b0da 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java @@ -26,6 +26,7 @@ import org.openecomp.sdc.be.components.impl.ResponseFormatManager; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException; import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder; import org.openecomp.sdc.common.log.wrappers.Logger; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component @@ -35,16 +36,22 @@ public class OperationExceptionMapper implements ExceptionMapper<OperationExcept private final ServletResponseBuilder servletResponseBuilder; private final ResponseFormatManager responseFormatManager; - private static final Logger log = Logger.getLogger(OperationExceptionMapper.class); + private static final Logger LOGGER = Logger.getLogger(OperationExceptionMapper.class); + @Autowired public OperationExceptionMapper(final ServletResponseBuilder servletResponseBuilder) { this.servletResponseBuilder = servletResponseBuilder; this.responseFormatManager = ResponseFormatManager.getInstance(); } + public OperationExceptionMapper(final ServletResponseBuilder servletResponseBuilder, final ResponseFormatManager responseFormatManager) { + this.servletResponseBuilder = servletResponseBuilder; + this.responseFormatManager = responseFormatManager; + } + @Override public Response toResponse(final OperationException exception) { - log.debug("Handling OperationException response", exception); + LOGGER.debug("Handling OperationException response", exception); return servletResponseBuilder.buildErrorResponse(responseFormatManager.getResponseFormat(exception.getActionStatus(), exception.getParams())); } } |