update documentation
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / externalapi / servlet / CrudExternalServlet.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
21 package org.openecomp.sdc.be.externalapi.servlet;
22
23 import java.io.IOException;
24 import java.util.Arrays;
25 import java.util.EnumMap;
26 import java.util.List;
27 import java.util.Optional;
28 import java.util.stream.Collectors;
29
30 import javax.inject.Singleton;
31 import javax.servlet.ServletContext;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.ws.rs.Consumes;
34 import javax.ws.rs.HeaderParam;
35 import javax.ws.rs.POST;
36 import javax.ws.rs.Path;
37 import javax.ws.rs.PathParam;
38 import javax.ws.rs.Produces;
39 import javax.ws.rs.core.Context;
40 import javax.ws.rs.core.MediaType;
41 import javax.ws.rs.core.Response;
42
43 import org.apache.commons.lang3.StringUtils;
44 import org.elasticsearch.common.Strings;
45 import org.json.simple.JSONObject;
46 import org.json.simple.parser.JSONParser;
47 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
48 import org.openecomp.sdc.be.components.impl.ImportUtils;
49 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
50 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
51 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase;
52 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
53 import org.openecomp.sdc.be.config.BeEcompErrorManager;
54 import org.openecomp.sdc.be.dao.api.ActionStatus;
55 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
56 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
57 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
58 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
59 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
60 import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
61 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
62 import org.openecomp.sdc.be.model.Component;
63 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
64 import org.openecomp.sdc.be.model.LifecycleStateEnum;
65 import org.openecomp.sdc.be.model.Resource;
66 import org.openecomp.sdc.be.model.User;
67 import org.openecomp.sdc.be.model.category.CategoryDefinition;
68 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
69 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
70 import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
71 import org.openecomp.sdc.be.servlets.RepresentationUtils;
72 import org.openecomp.sdc.be.utils.CommonBeUtils;
73 import org.openecomp.sdc.common.api.Constants;
74 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
75 import org.openecomp.sdc.common.datastructure.Wrapper;
76 import org.openecomp.sdc.common.util.ValidationUtils;
77 import org.openecomp.sdc.exception.ResponseFormat;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 import com.fasterxml.jackson.databind.ObjectMapper;
82 import com.jcabi.aspects.Loggable;
83
84 import fj.data.Either;
85 import io.swagger.annotations.Api;
86 import io.swagger.annotations.ApiImplicitParam;
87 import io.swagger.annotations.ApiImplicitParams;
88 import io.swagger.annotations.ApiOperation;
89 import io.swagger.annotations.ApiParam;
90 import io.swagger.annotations.ApiResponse;
91 import io.swagger.annotations.ApiResponses;
92
93 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
94 @Path("/v1/catalog")
95 @Api(value = "CRUD External Servlet", description = "This Servlet serves external users for creating assets and changing their lifecycle state")
96 @Singleton
97 public class CrudExternalServlet extends AbstractValidationsServlet {
98
99     @Context
100     private HttpServletRequest request;
101
102     private static final Logger log = LoggerFactory.getLogger(CrudExternalServlet.class);
103
104     /**
105      * Creates a new Resource
106      *
107      * @param assetType
108      * @param data
109      * @param userId
110      * @param instanceIdHeader
111      * @return
112      */
113     @POST
114     @Path("/{assetType}")
115     @Consumes(MediaType.APPLICATION_JSON)
116     @Produces(MediaType.APPLICATION_JSON)
117     @ApiOperation(value = "creates a resource", httpMethod = "POST", notes = "Creates a resource")
118     @ApiResponses(value = {
119             @ApiResponse(code = 200, message = "ECOMP component is authenticated and Asset created", response = Resource.class),
120             @ApiResponse(code = 400, message = "Missing  X-ECOMP-InstanceID  HTTP header - POL5001"),
121             @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
122             @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
123             @ApiResponse(code = 404, message = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
124             @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
125             @ApiResponse(code = 500, message = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000"),
126             @ApiResponse(code = 400, message = "The name provided for the newly created resource is already in use for another resource in SDC - SVC4050"),
127             @ApiResponse(code = 400, message = "Invalid field format. One of the provided fields does not comply with the field rules - SVC4126"),
128             @ApiResponse(code = 400, message = "Missing request body. The post request did not contain the expected body - SVC4500"),
129             @ApiResponse(code = 400, message = "The resource name is missing in the request body - SVC4062"),
130             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT description has wrong format - SVC4064"),
131             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT description has wrong format (exceeds limit) - SVC4065"),
132             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT tags exceeds character limit - SVC4066"),
133             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT vendor name exceeds character limit - SVC4067"),
134             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT vendor release exceeds character limit - SVC4068"),
135             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT ATT Contact has wrong format - SVC4069"),
136             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT name has wrong format - SVC4070"),
137             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT vendor name has wrong format - SVC4071"),
138             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT vendor release has wrong format - SVC4072"),
139             @ApiResponse(code = 400, message = "Create VFCMT request: VFCMT name exceeds character limit - SVC4073")})
140     @ApiImplicitParams({@ApiImplicitParam(required = true, dataType = "org.openecomp.sdc.be.model.Resource", paramType = "body", value = "json describe the created resource")})
141     public Response createResourceExternal(
142             @ApiParam(value = "Determines the format of the body of the request", required = true)@HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contenType,
143             @ApiParam(value = "The user id", required = true)@HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
144             @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
145             @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
146             @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
147             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
148             @ApiParam(value = "The requested asset type", required = true, allowableValues = "resources, services")@PathParam("assetType") final String assetType,
149             @ApiParam( hidden = true) String data) {
150
151         init(log);
152
153         Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
154         String requestURI = request.getRequestURI();
155         String url = request.getMethod() + " " + requestURI;
156         log.debug("Start handle request of {}", url);
157         Resource resource = null;
158         User modifier = null;
159         EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
160         ServletContext context = request.getSession().getServletContext();
161         ResourceBusinessLogic resourceBL = getResourceBL(context);
162         try {
163             // Validate X-ECOMP-InstanceID Header
164             if (responseWrapper.isEmpty()) {
165                 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
166             }
167             // Validate USER_ID Header
168             if (responseWrapper.isEmpty()) {
169                 validateHttpCspUserIdHeader(userId, responseWrapper);
170             }
171             // Validate assetType
172             if (responseWrapper.isEmpty()) {
173                 if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) ){
174                     responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
175                 }
176             }
177             //Validate resource type
178             if(responseWrapper.isEmpty()){
179                 JSONParser parser = new JSONParser();
180                 JSONObject jsonObj = (JSONObject) parser.parse(data);
181                 String resourceType = (String) jsonObj.get(FilterKeyEnum.RESOURCE_TYPE.getName());
182                 if( StringUtils.isEmpty(resourceType) || !ResourceTypeEnum.containsName(resourceType) ){
183                     additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, (String) jsonObj.get("name"));
184                     responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
185                 }
186             }
187             // Convert the user json to a resource
188             if (responseWrapper.isEmpty()) {
189                 modifier = new User();
190                 modifier.setUserId(userId);
191                 Either<Resource, ResponseFormat> eitherResource = getComponentsUtils()
192                         .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class,
193                                 null, ComponentTypeEnum.RESOURCE);
194                 if( eitherResource.isRight() ){
195                     responseWrapper.setInnerElement(eitherResource.right().value());
196                 }
197                 else{
198                     resource = eitherResource.left().value();
199                 }
200
201             }
202             //validate name exist
203             if(responseWrapper.isEmpty()){
204                 if( Strings.isEmpty(resource.getName())){
205                     responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
206                             ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()));
207
208                 }
209             }
210
211             if(responseWrapper.isEmpty()){
212                 resource.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
213                 resource.setSystemName(ValidationUtils.convertToSystemName(resource.getName()));
214                 resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VFCMT.name(),
215                         resource.getSystemName()));
216                 handleCategories(context, data, resource, responseWrapper);
217             }
218             // Create the resource in the dataModel
219             if (responseWrapper.isEmpty()) {
220                 Either<Resource, ResponseFormat> eitherCreateResponse = resourceBL.createResource(resource, null,
221                         modifier, null, null);
222                 if (eitherCreateResponse.isRight()) {
223                     responseWrapper.setInnerElement(eitherCreateResponse.right().value());
224                 } else {
225                     resource = eitherCreateResponse.left().value();
226                 }
227             }
228             Response response;
229             //Build Response and store it in the response Wrapper
230             if (responseWrapper.isEmpty()) {
231                 response = buildCreatedResourceResponse(resource, context, responseWrapper);
232             }
233             else{
234                 response = buildErrorResponse(responseWrapper.getInnerElement());
235             }
236             return response;
237
238         } catch (Exception e) {
239             final String message = "failed to create vfc monitoring template resource";
240             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message);
241             log.debug(message, e);
242             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
243         }
244         finally{
245             prepareAdditionalAudit(resource, additionalParams);
246
247             getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
248                     ComponentTypeEnum.RESOURCE.getValue(), AuditingActionEnum.CREATE_RESOURCE_BY_API.getName(), request,
249                     additionalParams);
250         }
251     }
252
253     /**
254      * Changing the lifecycle of an asset
255      * @param jsonChangeInfo    The description - request body
256      * @param assetType The requested asset type.Valid values are: resources / services (for VFCMT â€“ use "resources")
257      * @param uuid The uuid of the desired resource to be changed
258      * @param lifecycleTransition The lifecycle operation to be performed on the asset.Valid values are:Checkin / Checkout /  CERTIFICATION_REQUEST
259      * @param userId
260      * @return
261      */
262     @POST
263     @Path("/{assetType}/{uuid}/lifecycleState/{lifecycleOperation}")
264     @Consumes(MediaType.APPLICATION_JSON)
265     @Produces(MediaType.APPLICATION_JSON)
266     @ApiOperation(value = "Change Resource lifecycle State", httpMethod = "POST")
267     @ApiResponses(value = {
268             @ApiResponse(code = 200, message = "Resource state changed", response = AssetMetadata.class),
269             @ApiResponse(code = 400, message = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
270             @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
271             @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
272             @ApiResponse(code = 404, message = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
273             @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
274             @ApiResponse(code = 500, message = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000"),
275             @ApiResponse(code = 403, message = "Asset is already checked-out by another user - SVC4085"),
276             @ApiResponse(code = 403, message = "Asset is being edited by different user. Only one user can checkout and edit an asset on given time. The asset will be available for checkout after the other user will checkin the asset - SVC4080")})
277     @ApiImplicitParams({@ApiImplicitParam(required = true, dataType = "org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction", paramType = "body", value = "userRemarks - Short description (free text) about the asset version being changed")})
278     public Response changeResourceStateExternal(
279             @ApiParam(value = "Determines the format of the body of the request", required = true)@HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contenType,
280             @ApiParam(value = "The user id", required = true)@HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
281             @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
282             @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
283             @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
284             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
285             @ApiParam(allowableValues = "checkout, checkin", required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition,
286             @ApiParam(value = "id of component to be changed") @PathParam(value = "uuid") final String uuid,
287             @ApiParam(value = "validValues: resources / services ", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam(value = "assetType") final String assetType,
288             @ApiParam( hidden = true) String jsonChangeInfo) {
289
290         Response response = null;
291         EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
292
293         init(log);
294
295         String requestURI = request.getRequestURI();
296         String url = request.getMethod() + " " + requestURI;
297         log.debug("Start handle request of {}", url);
298
299         //get the business logic
300         ServletContext context = request.getSession().getServletContext();
301         LifecycleBusinessLogic businessLogic = getLifecycleBL(context);
302
303         Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);
304         ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
305         Component component = null;
306         Component responseObject = null;
307         User modifier = null;
308
309         try{
310             // Validate X-ECOMP-InstanceID Header
311             if (responseWrapper.isEmpty()) {
312                 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
313             }
314
315             if (responseWrapper.isEmpty()) {
316                 //get user
317                 Either<User, ResponseFormat> eitherGetUser = getUser(request, userId);
318                 if (eitherGetUser.isRight()) {
319                     ResponseFormat responseFormat = eitherGetUser.right().value();
320                     responseWrapper.setInnerElement(responseFormat);
321                     return buildErrorResponse(responseFormat);
322                 }
323                 modifier = eitherGetUser.left().value();
324
325                 //get the component id from the uuid
326                 Either<Component, ResponseFormat> latestVersion = businessLogic.getLatestComponentByUuid(componentType, uuid);
327                 if (latestVersion.isRight()) {
328                     ResponseFormat responseFormat = latestVersion.right().value();
329                     responseWrapper.setInnerElement(responseFormat);
330                     return buildErrorResponse(responseFormat);
331                 }
332                 component = latestVersion.left().value();
333                 String componentId = component.getUniqueId();
334
335                 //validate the transition is valid
336                 Either<LifeCycleTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(lifecycleTransition, modifier);
337                 if (validateEnum.isRight()) {
338                     ResponseFormat responseFormat = validateEnum.right().value();
339                     responseWrapper.setInnerElement(responseFormat);
340                     return buildErrorResponse(responseFormat);
341                 }
342                 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
343
344                 //create changeInfo
345                 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
346                 try {
347                     if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
348                         ObjectMapper mapper = new ObjectMapper();
349                         changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
350                     }
351                 }
352                 catch (Exception e) {
353                     BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
354                     log.debug("failed to convert from json {}", jsonChangeInfo, e);
355                     ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(modifier, componentId, AuditingActionEnum.CHECKOUT_RESOURCE);
356                     responseWrapper.setInnerElement(responseFormat);
357                     return buildErrorResponse(responseFormat);
358                 }
359
360                 //execute business logic
361                 Either<? extends Component, ResponseFormat> actionResponse = businessLogic.changeComponentState(componentType, componentId, modifier, transitionEnum, changeInfo, false, true);
362                 if (actionResponse.isRight()) {
363                     log.info("failed to change resource state");
364                     ResponseFormat responseFormat = actionResponse.right().value();
365                     responseWrapper.setInnerElement(responseFormat);
366                     return buildErrorResponse(responseFormat);
367                 }
368
369                 log.debug("change state successful !!!");
370                 responseObject = actionResponse.left().value();
371                 response = buildCreatedResourceResponse(responseObject, context, responseWrapper);
372             } else {
373                 response = buildErrorResponse(responseWrapper.getInnerElement());
374             }
375
376             return response;
377         } catch (Exception e) {
378             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State");
379             log.debug("change lifecycle state failed with exception", e);
380             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
381             responseWrapper.setInnerElement(responseFormat);
382             return buildErrorResponse(responseFormat);
383         } finally{
384             auditChnageLifecycleAction(additionalParams, responseWrapper, componentType, component, responseObject, modifier, userId);
385         }
386     }
387
388     private void prepareAdditionalAudit(Resource resource, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) {
389         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, StringUtils.EMPTY);
390         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, StringUtils.EMPTY);
391
392         if( resource != null ){
393             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, ImportUtils.Constants.FIRST_NON_CERTIFIED_VERSION);
394             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name());
395             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resource.getName());
396             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, resource.getUUID());
397             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, resource.getInvariantUUID());
398         } else {
399             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, StringUtils.EMPTY);
400             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, StringUtils.EMPTY);
401             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, StringUtils.EMPTY);
402             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, StringUtils.EMPTY);
403         }
404     }
405
406     private Response buildCreatedResourceResponse(Component resource, ServletContext context,
407             Wrapper<ResponseFormat> responseWrapper) throws IOException {
408         ResponseFormat responseFormat;
409         Response response;
410         AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
411         Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
412                 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(),
413                         true);
414         if (resMetadata.isRight()) {
415             log.debug("Asset conversion Failed");
416             responseFormat = resMetadata.right().value();
417             responseWrapper.setInnerElement(responseFormat);
418             response = buildErrorResponse(responseFormat);
419         }else{
420             final AssetMetadata assetData = resMetadata.left().value();
421             assetData.setToscaModelURL(null);
422
423             responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
424             Object representation = RepresentationUtils.toRepresentation(assetData);
425             response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
426         }
427         return response;
428     }
429
430     private void handleCategories(ServletContext context, String data, Resource resource,
431             Wrapper<ResponseFormat> responseWrapper) {
432         try {
433             JSONParser parser = new JSONParser();
434             JSONObject jsonObj = (JSONObject) parser.parse(data);
435             String category = (String) jsonObj.get(CategoryTypeEnum.CATEGORY.getValue());
436             String subcategory = (String) jsonObj.get(CategoryTypeEnum.SUBCATEGORY.getValue());
437             if (Strings.isEmpty(category)) {
438                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
439                         ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
440             }
441             else if (Strings.isEmpty(subcategory)) {
442                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
443                         ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
444             }
445             if (responseWrapper.isEmpty()) {
446                 ElementBusinessLogic elementLogic = getElementBL(context);
447                 // get All Categories
448                 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories = elementLogic
449                         .getAllResourceCategories();
450                 // Error fetching categories
451                 if (allResourceCategories.isRight()) {
452                     responseWrapper.setInnerElement(
453                             getComponentsUtils().getResponseFormat(allResourceCategories.right().value()));
454                 } else {
455                     addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
456                 }
457             }
458         } catch (Exception e) {
459             log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
460             responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
461         }
462
463     }
464
465     private void addCategories(Resource resource, String category, String subcategory,
466             Either<List<CategoryDefinition>, ActionStatus> allResourceCategories,
467             Wrapper<ResponseFormat> responseWrapper) {
468         Optional<CategoryDefinition> optionalCategory =
469                 // Stream of all the categories
470                 allResourceCategories.left().value().stream()
471                         // filter in only relevant category
472                         .filter(e -> e.getName().equals(category))
473                         // get the result
474                         .findAny();
475         if (!optionalCategory.isPresent()) {
476             responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
477                     ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
478         } else {
479             CategoryDefinition categoryDefinition = optionalCategory.get();
480
481             List<SubCategoryDefinition> subCaregories =
482                     // Stream of all sub-categories of the relevant
483                     // category
484                     categoryDefinition.getSubcategories().stream()
485                             // filter in only relevant sub-category
486                             .filter(e -> e.getName().equals(subcategory))
487                             // get the result
488                             .collect(Collectors.toList());
489
490             if( subCaregories.isEmpty() ){
491                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
492                         ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
493             }
494             else{
495                 categoryDefinition.setSubcategories(subCaregories);
496                 resource.setCategories(Arrays.asList(categoryDefinition));
497             }
498
499         }
500     }
501
502
503
504
505     private void auditChnageLifecycleAction(EnumMap<AuditingFieldsKeysEnum, Object> additionalParams,
506             Wrapper<ResponseFormat> responseWrapper, ComponentTypeEnum componentType, Component component,
507             Component responseObject, User modifier, String userId) {
508         if (modifier!=null){
509             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFullName());
510             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId());
511         } else {
512             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, "");
513             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, userId);
514         }
515
516         if (component!=null){
517             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, component.getName());
518             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, component.getVersion());
519             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, component.getLifecycleState().name());
520         } else {
521             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, "");
522             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, "");
523             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, "");
524         }
525
526         if (responseObject!=null){
527             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, responseObject.getVersion());
528             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, responseObject.getUUID());
529             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, responseObject.getInvariantUUID());
530             additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,responseObject.getLifecycleState().name());
531         } else {
532             if (component!=null){
533                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, component.getVersion());
534                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, component.getUUID());
535                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, component.getInvariantUUID());
536                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,component.getLifecycleState().name());
537             } else {
538                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, "");
539                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, "");
540                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, "");
541                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,"");
542             }
543         }
544
545         getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
546                 componentType.getValue(), AuditingActionEnum.CHANGE_LIFECYCLE_BY_API.getName(), request,
547                 additionalParams);
548     }
549
550     private Wrapper<ResponseFormat> runValidations(final String assetType) {
551         Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
552
553         // Validate X-ECOMP-InstanceID Header
554         if (responseWrapper.isEmpty()) {
555             String instanceId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
556             validateXECOMPInstanceIDHeader(instanceId,responseWrapper);
557         }
558         // Validate USER_ID Header
559         if (responseWrapper.isEmpty()) {
560             validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER),responseWrapper);
561         }
562         // Validate assetType
563         if (responseWrapper.isEmpty()) {
564             if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) &&  !AssetTypeEnum.SERVICES.getValue().equals(assetType)){
565                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
566             }
567         }
568
569         return responseWrapper;
570     }
571
572     private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
573         LifeCycleTransitionEnum transitionEnum = LifeCycleTransitionEnum.CHECKOUT;
574         try {
575             transitionEnum = LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition);
576         } catch (IllegalArgumentException e) {
577             log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString(), e);
578             ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, "", AuditingActionEnum.CHECKOUT_RESOURCE);
579             return Either.right(error);
580         }
581         return Either.left(transitionEnum);
582     }
583
584 }