08f26fff4a4c7d88a8f78f96130d202876556569
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / servlets / ResourcesServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.servlets;
21
22 import com.jcabi.aspects.Loggable;
23 import fj.data.Either;
24 import io.swagger.v3.oas.annotations.Operation;
25 import io.swagger.v3.oas.annotations.Parameter;
26 import io.swagger.v3.oas.annotations.media.ArraySchema;
27 import io.swagger.v3.oas.annotations.media.Content;
28 import io.swagger.v3.oas.annotations.media.Schema;
29 import io.swagger.v3.oas.annotations.responses.ApiResponse;
30 import io.swagger.v3.oas.annotations.servers.Server;
31 import io.swagger.v3.oas.annotations.servers.Servers;
32 import io.swagger.v3.oas.annotations.tags.Tag;
33 import io.swagger.v3.oas.annotations.tags.Tags;
34 import java.io.File;
35 import java.io.IOException;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import javax.inject.Inject;
40 import javax.servlet.ServletContext;
41 import javax.servlet.http.HttpServletRequest;
42 import javax.ws.rs.Consumes;
43 import javax.ws.rs.DELETE;
44 import javax.ws.rs.GET;
45 import javax.ws.rs.HeaderParam;
46 import javax.ws.rs.POST;
47 import javax.ws.rs.PUT;
48 import javax.ws.rs.Path;
49 import javax.ws.rs.PathParam;
50 import javax.ws.rs.Produces;
51 import javax.ws.rs.QueryParam;
52 import javax.ws.rs.core.Context;
53 import javax.ws.rs.core.MediaType;
54 import javax.ws.rs.core.Response;
55 import org.apache.http.HttpStatus;
56 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
57 import org.glassfish.jersey.media.multipart.FormDataParam;
58 import org.json.JSONException;
59 import org.json.JSONObject;
60 import org.keycloak.representations.AccessToken;
61 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
62 import org.openecomp.sdc.be.components.impl.CsarValidationUtils;
63 import org.openecomp.sdc.be.components.impl.ImportUtils;
64 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
65 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
66 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
67 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
68 import org.openecomp.sdc.be.config.BeEcompErrorManager;
69 import org.openecomp.sdc.be.dao.api.ActionStatus;
70 import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum;
71 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
72 import org.openecomp.sdc.be.datatypes.enums.DeleteActionEnum;
73 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
74 import org.openecomp.sdc.be.impl.ComponentsUtils;
75 import org.openecomp.sdc.be.impl.ServletUtils;
76 import org.openecomp.sdc.be.model.Resource;
77 import org.openecomp.sdc.be.model.UploadResourceInfo;
78 import org.openecomp.sdc.be.model.User;
79 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
80 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
81 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo;
82 import org.openecomp.sdc.be.servlets.ResourceUploadServlet.ResourceAuthorityTypeEnum;
83 import org.openecomp.sdc.common.api.Constants;
84 import org.openecomp.sdc.common.datastructure.Wrapper;
85 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
86 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
87 import org.openecomp.sdc.common.log.enums.StatusCode;
88 import org.openecomp.sdc.common.log.wrappers.Logger;
89 import org.openecomp.sdc.common.util.ValidationUtils;
90 import org.openecomp.sdc.common.zip.exception.ZipException;
91 import org.openecomp.sdc.exception.ResponseFormat;
92 import org.openecomp.sdc.common.util.Multitenancy;
93 import org.springframework.stereotype.Controller;
94
95 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
96 @Path("/v1/catalog")
97 @Tags({@Tag(name = "SDCE-2 APIs")})
98 @Servers({@Server(url = "/sdc2/rest")})
99 @Controller
100 public class ResourcesServlet extends AbstractValidationsServlet {
101
102     private static final Logger log = Logger.getLogger(ResourcesServlet.class);
103     private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ResourcesServlet.class.getName());
104     private static final String START_HANDLE_REQUEST_OF = "Start handle request of {}";
105     private static final String MODIFIER_ID_IS = "modifier id is {}";
106     private final ResourceBusinessLogic resourceBusinessLogic;
107
108     @Inject
109     public ResourcesServlet(ComponentInstanceBusinessLogic componentInstanceBL,
110                             ResourceBusinessLogic resourceBusinessLogic, ComponentsUtils componentsUtils, ServletUtils servletUtils,
111                             ResourceImportManager resourceImportManager) {
112         super(componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
113         this.resourceBusinessLogic = resourceBusinessLogic;
114     }
115
116     @POST
117     @Path("/resources")
118     @Consumes(MediaType.APPLICATION_JSON)
119     @Produces(MediaType.APPLICATION_JSON)
120     @Operation(description = "Create Resource", method = "POST", summary = "Returns created resource", responses = {
121             @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
122             @ApiResponse(responseCode = "201", description = "Resource created"),
123             @ApiResponse(responseCode = "403", description = "Restricted operation"),
124             @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
125             @ApiResponse(responseCode = "409", description = "Resource already exist"),
126             @ApiResponse(responseCode = "401", description = "Unauthorized Tenant")})
127     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
128     public Response createResource(@Parameter(description = "Resource object to be created", required = true) String data,
129                                    @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId)
130         throws IOException, ZipException {
131         userId = (userId != null) ? userId : request.getHeader(Constants.USER_ID_HEADER);
132         init();
133         String url = request.getMethod() + " " + request.getRequestURI();
134         log.debug(START_HANDLE_REQUEST_OF, url);
135         // get modifier id
136         User modifier = new User();
137         modifier.setUserId(userId);
138         log.debug(MODIFIER_ID_IS, userId);
139         loggerSupportability.log(LoggerSupportabilityActions.CREATE_RESOURCE, StatusCode.STARTED, "Starting to create Resource by user {}", userId);
140         Response response;
141         try {
142             Wrapper<Response> responseWrapper = new Wrapper<>();
143             // UI Import
144             if (isUIImport(data)) {
145                 performUIImport(responseWrapper, data, request, userId, null);
146             }
147             // UI Create
148             else {
149                 Either<Resource, ResponseFormat> convertResponse = parseToResource(data, modifier);
150                 if (convertResponse.isRight()) {
151                     log.debug("failed to parse resource");
152                     response = buildErrorResponse(convertResponse.right().value());
153                     return response;
154                 }
155                 Multitenancy keyaccess = new Multitenancy();
156                 Resource resource = convertResponse.left().value();
157                 if (keyaccess.multiTenancyCheck())
158                 {
159                         AccessToken.Access realmAccess = keyaccess.getAccessToken(request).getRealmAccess();
160                         Set<String> realmroles = realmAccess.getRoles();
161                         boolean match = realmroles.contains(resource.getTenant());
162                         if (match) {
163                             Resource createdResource = resourceBusinessLogic.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, modifier, null, null);
164                             Object representation = RepresentationUtils.toRepresentation(createdResource);
165                             response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
166                             responseWrapper.setInnerElement(response);
167                             loggerSupportability
168                                     .log(LoggerSupportabilityActions.CREATE_RESOURCE, resource.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
169                                             "Resource successfully created user {}", userId);
170                         } else {
171                             return Response.status(401, "Unauthorized Tenant").build();
172                         }
173                 } else {
174                     Resource createdResource = resourceBusinessLogic.createResource(resource, AuditingActionEnum.CREATE_RESOURCE, modifier, null, null);
175                     Object representation = RepresentationUtils.toRepresentation(createdResource);
176                     response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
177                     responseWrapper.setInnerElement(response);
178                     loggerSupportability
179                             .log(LoggerSupportabilityActions.CREATE_RESOURCE, resource.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
180                                     "Resource successfully created user {}", userId);
181                 }
182             }
183             return responseWrapper.getInnerElement();
184         } catch (final IOException | ZipException e) {
185             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Resource");
186             log.debug("create resource failed with exception", e);
187             throw e;
188         }
189     }
190
191     private boolean isUIImport(String data) {
192         boolean isUIImport;
193         try {
194             JSONObject json = new JSONObject(data);
195             String payloadName = json.getString(ImportUtils.Constants.UI_JSON_PAYLOAD_NAME);
196             isUIImport = payloadName != null && !payloadName.isEmpty();
197         } catch (JSONException e) {
198             log.debug("failed to parse json sent from client, json:{}", data, e);
199             isUIImport = false;
200         }
201         return isUIImport;
202     }
203
204     private void performUIImport(final Wrapper<Response> responseWrapper, final String data, final HttpServletRequest request, final String userId,
205                                  final String resourceUniqueId) throws ZipException {
206         Wrapper<User> userWrapper = new Wrapper<>();
207         Wrapper<UploadResourceInfo> uploadResourceInfoWrapper = new Wrapper<>();
208         Wrapper<String> yamlStringWrapper = new Wrapper<>();
209         ResourceAuthorityTypeEnum resourceAuthorityEnum = ResourceAuthorityTypeEnum.USER_TYPE_UI;
210         commonGeneralValidations(responseWrapper, userWrapper, uploadResourceInfoWrapper, resourceAuthorityEnum, userId, data);
211         if (!CsarValidationUtils.isCsarPayloadName(uploadResourceInfoWrapper.getInnerElement().getPayloadName())) {
212             fillPayload(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), data, resourceAuthorityEnum,
213                 null);
214             // PayLoad Validations
215             commonPayloadValidations(responseWrapper, yamlStringWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement());
216         }
217         specificResourceAuthorityValidations(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(), request,
218             data, resourceAuthorityEnum);
219         if (responseWrapper.isEmpty()) {
220             handleImport(responseWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement(),
221                 yamlStringWrapper.getInnerElement(), resourceAuthorityEnum, true, resourceUniqueId);
222         }
223     }
224
225     private Either<Resource, ResponseFormat> parseToResource(String resourceJson, User user) {
226         return getComponentsUtils()
227             .convertJsonToObjectUsingObjectMapper(resourceJson, user, Resource.class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.RESOURCE);
228     }
229
230     private Either<Resource, ResponseFormat> parseToLightResource(String resourceJson, User user) {
231         Either<Resource, ResponseFormat> ret = getComponentsUtils()
232             .convertJsonToObjectUsingObjectMapper(resourceJson, user, Resource.class, AuditingActionEnum.UPDATE_RESOURCE_METADATA,
233                 ComponentTypeEnum.RESOURCE);
234         if (ret.isLeft()) {// drop unwanted data (sent from UI in update flow)
235             ret.left().value().setRequirements(null);
236             ret.left().value().setCapabilities(null);
237         }
238         return ret;
239     }
240
241     @DELETE
242     @Path("/resources/{resourceId}")
243     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
244     public Response deleteResource(@PathParam("resourceId") final String resourceId,
245                                    @Parameter(description = "Optional parameter to determine the delete action: " +
246                                        "DELETE, which will permanently delete the Resource from the system or " +
247                                        "MARK_AS_DELETE, which will logically mark the Resource as deleted. Default action is to MARK_AS_DELETE")
248                                    @QueryParam("deleteAction") final DeleteActionEnum deleteAction,
249                                    @Context final HttpServletRequest request) {
250         String url = request.getMethod() + " " + request.getRequestURI();
251         log.debug(START_HANDLE_REQUEST_OF, url);
252         // get modifier id
253         String userId = request.getHeader(Constants.USER_ID_HEADER);
254         User modifier = new User();
255         modifier.setUserId(userId);
256         log.debug(MODIFIER_ID_IS, userId);
257         loggerSupportability.log(LoggerSupportabilityActions.DELETE_RESOURCE, StatusCode.STARTED, "Starting to delete Resource by user {}", userId);
258         try {
259             String resourceIdLower = resourceId.toLowerCase();
260             ResponseFormat actionResponse;
261             if (DeleteActionEnum.DELETE.equals(deleteAction)) {
262                 resourceBusinessLogic.deleteResourceAllVersions(resourceId, modifier);
263                 actionResponse = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT);
264             } else {
265                 actionResponse = resourceBusinessLogic.deleteResource(resourceIdLower, modifier);
266             }
267             if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) {
268                 log.debug("failed to delete resource");
269                 return buildErrorResponse(actionResponse);
270             }
271
272             loggerSupportability.log(LoggerSupportabilityActions.DELETE_RESOURCE, StatusCode.COMPLETE, "Ended delete Resource by user {}", userId);
273             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null);
274         } catch (Exception e) {
275             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Resource");
276             log.debug("delete resource failed with exception ", e);
277             throw e;
278         }
279     }
280
281     @DELETE
282     @Path("/resources/{resourceName}/{version}")
283     @Operation(description = "Delete Resource By Name And Version", method = "DELETE", summary = "Returns no content", responses = {
284         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
285         @ApiResponse(responseCode = "204", description = "Resource deleted"),
286         @ApiResponse(responseCode = "403", description = "Restricted operation"),
287         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
288         @ApiResponse(responseCode = "404", description = "Resource not found")})
289     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
290     public Response deleteResourceByNameAndVersion(@PathParam("resourceName") final String resourceName, @PathParam("version") final String version,
291                                                    @Context final HttpServletRequest request) {
292         ServletContext context = request.getSession().getServletContext();
293         String url = request.getMethod() + " " + request.getRequestURI();
294         log.debug(START_HANDLE_REQUEST_OF, url);
295         // get modifier id
296         String userId = request.getHeader(Constants.USER_ID_HEADER);
297         User modifier = new User();
298         modifier.setUserId(userId);
299         log.debug(MODIFIER_ID_IS, userId);
300         Response response;
301         ResourceBusinessLogic businessLogic = getResourceBL(context);
302         ResponseFormat actionResponse = businessLogic.deleteResourceByNameAndVersion(resourceName, version, modifier);
303         if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) {
304             log.debug("failed to delete resource");
305             response = buildErrorResponse(actionResponse);
306             return response;
307         }
308         response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null);
309         return response;
310     }
311
312     @GET
313     @Path("/resources/{resourceId}")
314     @Consumes(MediaType.APPLICATION_JSON)
315     @Produces(MediaType.APPLICATION_JSON)
316     @Operation(description = "Retrieve Resource", method = "GET", summary = "Returns resource according to resourceId", responses = {
317         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
318         @ApiResponse(responseCode = "200", description = "Resource found"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
319         @ApiResponse(responseCode = "404", description = "Resource not found")})
320     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
321     public Response getResourceById(@PathParam("resourceId") final String resourceId, @Context final HttpServletRequest request,
322                                     @HeaderParam(value = Constants.USER_ID_HEADER) String userId) throws IOException {
323         ServletContext context = request.getSession().getServletContext();
324         String url = request.getMethod() + " " + request.getRequestURI();
325         log.debug(START_HANDLE_REQUEST_OF, url);
326         // get modifier id
327         User modifier = new User();
328         modifier.setUserId(userId);
329         log.debug(MODIFIER_ID_IS, userId);
330         Response response;
331         try {
332             String resourceIdLower = resourceId.toLowerCase();
333             log.trace("get resource with id {}", resourceId);
334             Either<Resource, ResponseFormat> actionResponse = resourceBusinessLogic.getResource(resourceIdLower, modifier);
335             if (actionResponse.isRight()) {
336                 log.debug("failed to get resource");
337                 response = buildErrorResponse(actionResponse.right().value());
338                 return response;
339             }
340             Object resource = RepresentationUtils.toRepresentation(actionResponse.left().value());
341             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resource);
342         } catch (IOException e) {
343             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Resource");
344             log.debug("get resource failed with exception", e);
345             throw e;
346         }
347     }
348
349     @GET
350     @Path("/resources/resourceName/{resourceName}/resourceVersion/{resourceVersion}")
351     @Consumes(MediaType.APPLICATION_JSON)
352     @Produces(MediaType.APPLICATION_JSON)
353     @Operation(description = "Retrieve Resource by name and version", method = "GET", summary = "Returns resource according to resourceId", responses = {
354         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
355         @ApiResponse(responseCode = "200", description = "Resource found"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
356         @ApiResponse(responseCode = "404", description = "Resource not found")})
357     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
358     public Response getResourceByNameAndVersion(@PathParam("resourceName") final String resourceName,
359                                                 @PathParam("resourceVersion") final String resourceVersion, @Context final HttpServletRequest request,
360                                                 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) throws IOException {
361         // get modifier id
362         User modifier = new User();
363         modifier.setUserId(userId);
364         log.debug(MODIFIER_ID_IS, userId);
365         Response response;
366         try {
367             Either<Resource, ResponseFormat> actionResponse = resourceBusinessLogic
368                 .getResourceByNameAndVersion(resourceName, resourceVersion, userId);
369             if (actionResponse.isRight()) {
370                 response = buildErrorResponse(actionResponse.right().value());
371                 return response;
372             }
373             Object resource = RepresentationUtils.toRepresentation(actionResponse.left().value());
374             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resource);
375         } catch (IOException e) {
376             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Resource by name and version");
377             log.debug("get resource failed with exception", e);
378             throw e;
379         }
380     }
381
382     @GET
383     @Path("/resources/validate-name/{resourceName}")
384     @Consumes(MediaType.APPLICATION_JSON)
385     @Produces(MediaType.APPLICATION_JSON)
386     @Operation(description = "validate resource name", method = "GET", summary = "checks if the chosen resource name is available ", responses = {
387         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
388         @ApiResponse(responseCode = "200", description = "Resource found"), @ApiResponse(responseCode = "403", description = "Restricted operation")})
389     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
390     public Response validateResourceName(@PathParam("resourceName") final String resourceName, @QueryParam("subtype") String resourceType,
391                                          @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
392         String url = request.getMethod() + " " + request.getRequestURI();
393         log.debug(START_HANDLE_REQUEST_OF, url);
394         // get modifier id
395         User modifier = new User();
396         modifier.setUserId(userId);
397         log.debug(MODIFIER_ID_IS, userId);
398         Response response;
399         if (resourceType != null && !ResourceTypeEnum.containsName(resourceType)) {
400             log.debug("invalid resource type received");
401             response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
402             return response;
403         }
404         ResourceTypeEnum typeEnum = null;
405         if (resourceType != null) {
406             typeEnum = ResourceTypeEnum.valueOf(resourceType);
407         }
408         Either<Map<String, Boolean>, ResponseFormat> actionResponse = resourceBusinessLogic
409             .validateResourceNameExists(resourceName, typeEnum, userId);
410         if (actionResponse.isRight()) {
411             log.debug("failed to validate resource name");
412             response = buildErrorResponse(actionResponse.right().value());
413             return response;
414         }
415         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value());
416     }
417
418     @GET
419     @Path("/resources/certified/abstract")
420     @Consumes(MediaType.APPLICATION_JSON)
421     @Produces(MediaType.APPLICATION_JSON)
422     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
423     public Response getCertifiedAbstractResources(@Context final HttpServletRequest request,
424                                                   @HeaderParam(value = Constants.USER_ID_HEADER) String userId) throws IOException {
425         String url = request.getMethod() + " " + request.getRequestURI();
426         log.debug("(get) Start handle request of {}", url);
427         try {
428             List<Resource> resources = resourceBusinessLogic.getAllCertifiedResources(true, HighestFilterEnum.HIGHEST_ONLY, userId);
429             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), RepresentationUtils.toRepresentation(resources));
430         } catch (IOException e) {
431             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Abstract Resources");
432             log.debug("getCertifiedAbstractResources failed with exception", e);
433             throw e;
434         }
435     }
436
437     @GET
438     @Path("/resources/certified/notabstract")
439     @Consumes(MediaType.APPLICATION_JSON)
440     @Produces(MediaType.APPLICATION_JSON)
441     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
442     public Response getCertifiedNotAbstractResources(@Context final HttpServletRequest request,
443                                                      @HeaderParam(value = Constants.USER_ID_HEADER) String userId) throws IOException {
444         String url = request.getMethod() + " " + request.getRequestURI();
445         log.debug("(get) Start handle request of {}", url);
446         try {
447             List<Resource> resouces = resourceBusinessLogic.getAllCertifiedResources(false, HighestFilterEnum.ALL, userId);
448             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), RepresentationUtils.toRepresentation(resouces));
449         } catch (IOException e) {
450             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Certified Non Abstract Resources");
451             log.debug("getCertifiedNotAbstractResources failed with exception", e);
452             throw e;
453         }
454     }
455
456     @PUT
457     @Path("/resources/{resourceId}/metadata")
458     @Consumes(MediaType.APPLICATION_JSON)
459     @Produces(MediaType.APPLICATION_JSON)
460     @Operation(description = "Update Resource Metadata", method = "PUT", summary = "Returns updated resource metadata", responses = {
461         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
462         @ApiResponse(responseCode = "200", description = "Resource metadata updated"),
463         @ApiResponse(responseCode = "403", description = "Restricted operation"),
464         @ApiResponse(responseCode = "400", description = "Invalid content")})
465     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
466     public Response updateResourceMetadata(@PathParam("resourceId") final String resourceId,
467                                            @Parameter(description = "Resource metadata to be updated", required = true) String data,
468                                            @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId)
469         throws IOException {
470         String url = request.getMethod() + " " + request.getRequestURI();
471         log.debug(START_HANDLE_REQUEST_OF, url);
472         // get modifier id
473         User modifier = new User();
474         modifier.setUserId(userId);
475         log.debug(MODIFIER_ID_IS, userId);
476         Response response;
477         try {
478             String resourceIdLower = resourceId.toLowerCase();
479             Either<Resource, ResponseFormat> updateInfoResource = getComponentsUtils()
480                 .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class, AuditingActionEnum.UPDATE_RESOURCE_METADATA,
481                     ComponentTypeEnum.RESOURCE);
482             if (updateInfoResource.isRight()) {
483                 log.debug("failed to parse resource metadata");
484                 response = buildErrorResponse(updateInfoResource.right().value());
485                 return response;
486             }
487             Resource updatedResource = resourceBusinessLogic
488                 .updateResourceMetadata(resourceIdLower, updateInfoResource.left().value(), null, modifier, false);
489             Object resource = RepresentationUtils.toRepresentation(updatedResource);
490             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), resource);
491         } catch (IOException e) {
492             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource Metadata");
493             log.debug("Update Resource Metadata failed with exception", e);
494             throw e;
495         }
496     }
497
498     @PUT
499     @Path("/resources/{resourceId}")
500     @Consumes(MediaType.APPLICATION_JSON)
501     @Produces(MediaType.APPLICATION_JSON)
502     @Operation(description = "Update Resource", method = "PUT", summary = "Returns updated resource", responses = {
503         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
504         @ApiResponse(responseCode = "200", description = "Resource updated"),
505         @ApiResponse(responseCode = "403", description = "Restricted operation"),
506         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
507         @ApiResponse(responseCode = "409", description = "Resource already exist")})
508     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
509     public Response updateResource(@Parameter(description = "Resource object to be updated", required = true) String data,
510                                    @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
511                                    @PathParam(value = "resourceId") String resourceId) throws IOException, ZipException {
512         userId = (userId != null) ? userId : request.getHeader(Constants.USER_ID_HEADER);
513         init();
514         String url = request.getMethod() + " " + request.getRequestURI();
515         log.debug(START_HANDLE_REQUEST_OF, url);
516         // get modifier id
517         User modifier = new User();
518         modifier.setUserId(userId);
519         log.debug(MODIFIER_ID_IS, userId);
520         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_RESOURCE, StatusCode.STARTED, "Starting to update a resource by user {}", userId);
521         Response response;
522         try {
523             Wrapper<Response> responseWrapper = new Wrapper<>();
524             // UI Import
525             if (isUIImport(data)) {
526                 performUIImport(responseWrapper, data, request, userId, resourceId);
527             } else {
528                 Either<Resource, ResponseFormat> convertResponse = parseToLightResource(data, modifier);
529                 if (convertResponse.isRight()) {
530                     log.debug("failed to parse resource");
531                     response = buildErrorResponse(convertResponse.right().value());
532                     return response;
533                 }
534                 Resource updatedResource = resourceBusinessLogic
535                     .validateAndUpdateResourceFromCsar(convertResponse.left().value(), modifier, null, null, resourceId);
536                 Object representation = RepresentationUtils.toRepresentation(updatedResource);
537                 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation);
538                 responseWrapper.setInnerElement(response);
539                 loggerSupportability
540                     .log(LoggerSupportabilityActions.UPDATE_RESOURCE, updatedResource.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
541                         "Ended update a resource by user {}", userId);
542             }
543             return responseWrapper.getInnerElement();
544         } catch (final IOException | ZipException e) {
545             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Resource");
546             log.debug("update resource failed with exception", e);
547             throw e;
548         }
549     }
550
551     @GET
552     @Path("/resources/csar/{csaruuid}")
553     @Consumes(MediaType.APPLICATION_JSON)
554     @Produces(MediaType.APPLICATION_JSON)
555     @Operation(description = "Create Resource", method = "POST", summary = "Returns resource created from csar uuid", responses = {
556         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
557         @ApiResponse(responseCode = "201", description = "Resource retrieced"),
558         @ApiResponse(responseCode = "403", description = "Restricted operation"),
559         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
560     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
561     public Response getResourceFromCsar(@Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
562                                         @PathParam(value = "csaruuid") String csarUUID) throws IOException {
563         init();
564         String url = request.getMethod() + " " + request.getRequestURI();
565         log.debug(START_HANDLE_REQUEST_OF, url);
566         // retrieve user details
567         userId = (userId != null) ? userId : request.getHeader(Constants.USER_ID_HEADER);
568         User user = new User();
569         user.setUserId(userId);
570         log.debug("user id is {}", userId);
571         Response response;
572         try {
573             Either<Resource, ResponseFormat> eitherResource = resourceBusinessLogic
574                 .getLatestResourceFromCsarUuid(ValidationUtils.sanitizeInputString(csarUUID), user);
575             // validate response
576             if (eitherResource.isRight()) {
577                 log.debug("failed to get resource from csarUuid : {}", csarUUID);
578                 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT), eitherResource.right().value());
579             } else {
580                 Object representation = RepresentationUtils.toRepresentation(eitherResource.left().value());
581                 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation);
582             }
583             return response;
584         } catch (IOException e) {
585             log.debug("get resource by csar failed with exception", e);
586             throw e;
587         }
588     }
589
590     @POST
591     @Path("/resources/importReplaceResource")
592     @Produces(MediaType.APPLICATION_JSON)
593     @Operation(description = "Import Resource", method = "POST", summary = "Returns imported resource", responses = {
594         @ApiResponse(responseCode = "201", description = "Resource created"),
595         @ApiResponse(responseCode = "403", description = "Restricted operation"),
596         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
597         @ApiResponse(responseCode = "409", description = "Resource already exist")})
598     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
599     public Response importReplaceResource(
600         @Parameter(description = "The user id", required = true) @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
601         @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
602         @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
603         @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
604         @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
605         @Context final HttpServletRequest request, @Parameter(description = "FileInputStream") @FormDataParam("resourceZip") File file,
606         @Parameter(description = "ContentDisposition") @FormDataParam("resourceZip") FormDataContentDisposition contentDispositionHeader,
607         @Parameter(description = "resourceMetadata") @FormDataParam("resourceZipMetadata") String resourceInfoJsonString) {
608         init();
609         String requestURI = request.getRequestURI();
610         String url = request.getMethod() + " " + requestURI;
611         log.debug("importReplaceResource,Start handle request of {}", url);
612         // get modifier id
613         User modifier = new User();
614         modifier.setUserId(userId);
615         log.debug("importReplaceResource,modifier id is {}", userId);
616         log.debug("importReplaceResource,get file:{},fileName:{}", file, file.getName());
617         Response response;
618         ResponseFormat responseFormat = null;
619         AuditingActionEnum auditingActionEnum = AuditingActionEnum.Import_Replace_Resource;
620         String assetType = "resources";
621         ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
622         ResourceCommonInfo resourceCommonInfo = new ResourceCommonInfo(componentType.getValue());
623         DistributionData distributionData = new DistributionData(instanceIdHeader, requestURI);
624         // Mandatory
625         if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
626             log.debug("importReplaceResource: Missing X-ECOMP-InstanceID header");
627             responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
628             getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, distributionData, resourceCommonInfo, requestId, null);
629             return buildErrorResponse(responseFormat);
630         }
631         try {
632             Wrapper<Response> responseWrapper = new Wrapper<>();
633             // file import
634             Wrapper<User> userWrapper = new Wrapper<>();
635             Wrapper<UploadResourceInfo> uploadResourceInfoWrapper = new Wrapper<>();
636             Wrapper<String> yamlStringWrapper = new Wrapper<>();
637             ResourceAuthorityTypeEnum serviceAuthorityEnum = ResourceAuthorityTypeEnum.CSAR_TYPE_BE;
638             // PayLoad Validations
639             commonGeneralValidations(responseWrapper, userWrapper, uploadResourceInfoWrapper, serviceAuthorityEnum, userId, resourceInfoJsonString);
640             fillPayload(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, modifier, resourceInfoJsonString, serviceAuthorityEnum, file);
641             specificResourceAuthorityValidations(responseWrapper, uploadResourceInfoWrapper, yamlStringWrapper, userWrapper.getInnerElement(),
642                 request, resourceInfoJsonString, serviceAuthorityEnum);
643             log.debug("importReplaceResource:get payload:{}", uploadResourceInfoWrapper.getInnerElement().getPayloadData());
644             log.debug("importReplaceResource:get ResourceType:{}", uploadResourceInfoWrapper.getInnerElement().getResourceType());
645             if (responseWrapper.isEmpty()) {
646                 log.debug("importReplaceService:start handleImport");
647                 handleImport(responseWrapper, userWrapper.getInnerElement(), uploadResourceInfoWrapper.getInnerElement(),
648                     yamlStringWrapper.getInnerElement(), serviceAuthorityEnum, true, null);
649             }
650             return responseWrapper.getInnerElement();
651         } catch (ZipException e) {
652             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Import Resource");
653             log.debug("import resource failed with exception", e);
654             response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
655             return response;
656         }
657     }
658 }