[sdc] - latest swagger, dependencies, tests fix
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / externalapi / servlet / AssetsDataServlet.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.ByteArrayInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.util.Arrays;
27 import java.util.EnumMap;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Optional;
32 import java.util.stream.Collectors;
33
34 import javax.inject.Singleton;
35 import javax.servlet.ServletContext;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.ws.rs.Consumes;
38 import javax.ws.rs.GET;
39 import javax.ws.rs.HeaderParam;
40 import javax.ws.rs.POST;
41 import javax.ws.rs.Path;
42 import javax.ws.rs.PathParam;
43 import javax.ws.rs.Produces;
44 import javax.ws.rs.QueryParam;
45 import javax.ws.rs.core.Context;
46 import javax.ws.rs.core.MediaType;
47 import javax.ws.rs.core.Response;
48
49 import org.apache.commons.lang3.StringUtils;
50 import org.apache.commons.lang3.tuple.ImmutablePair;
51 import org.codehaus.jackson.JsonGenerationException;
52 import org.codehaus.jackson.map.JsonMappingException;
53 import org.codehaus.jackson.map.ObjectMapper;
54 import org.elasticsearch.common.Strings;
55 import org.json.simple.JSONObject;
56 import org.json.simple.parser.JSONParser;
57 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
58 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
59 import org.openecomp.sdc.be.components.impl.ImportUtils;
60 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
61 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
62 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase;
63 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
64 import org.openecomp.sdc.be.config.BeEcompErrorManager;
65 import org.openecomp.sdc.be.dao.api.ActionStatus;
66 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
67 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
68 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
69 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
70 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
71 import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
72 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
73 import org.openecomp.sdc.be.model.Component;
74 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
75 import org.openecomp.sdc.be.model.LifecycleStateEnum;
76 import org.openecomp.sdc.be.model.Resource;
77 import org.openecomp.sdc.be.model.User;
78 import org.openecomp.sdc.be.model.category.CategoryDefinition;
79 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
80 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
81 import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
82 import org.openecomp.sdc.be.servlets.RepresentationUtils;
83 import org.openecomp.sdc.be.utils.CommonBeUtils;
84 import org.openecomp.sdc.common.api.Constants;
85 import org.openecomp.sdc.common.config.EcompErrorName;
86 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
87 import org.openecomp.sdc.common.datastructure.Wrapper;
88 import org.openecomp.sdc.common.util.GeneralUtility;
89 import org.openecomp.sdc.common.util.ValidationUtils;
90 import org.openecomp.sdc.exception.ResponseFormat;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
93
94 import com.jcabi.aspects.Loggable;
95
96 import fj.data.Either;
97 import io.swagger.annotations.Api;
98 import io.swagger.annotations.ApiOperation;
99 import io.swagger.annotations.ApiParam;
100 import io.swagger.annotations.ApiResponse;
101 import io.swagger.annotations.ApiResponses;
102
103 /**
104  * This Servlet serves external users for retrieving component metadata.
105  * 
106  * @author tgitelman
107  *
108  */
109
110 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
111 @Path("/v1/catalog")
112 @Api(value = "Asset Metadata External Servlet", description = "This Servlet serves external users for retrieving component metadata.")
113 @Singleton
114 public class AssetsDataServlet extends AbstractValidationsServlet {
115
116         @Context
117         private HttpServletRequest request;
118
119         private static Logger log = LoggerFactory.getLogger(AssetsDataServlet.class.getName());
120         
121         /**
122          * 
123          * @param assetType
124          * @param category
125          * @param subCategory
126          * @param distributionStatus
127          * @param resourceType
128          * @param instanceIdHeader
129          * @return
130          */
131         @GET
132         @Path("/{assetType}")
133         @Produces(MediaType.APPLICATION_JSON)
134         @ApiOperation(value = "Fetch list of assets", httpMethod = "GET", notes = "Returns list of assets", response = AssetMetadata.class, responseContainer="List")
135         @ApiResponses(value = {
136                         @ApiResponse(code = 200, message = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", response = AssetMetadata.class, responseContainer="List"),
137                         @ApiResponse(code = 400, message = "Missing  “X-ECOMP-InstanceID”  HTTP header - POL5001"),
138                         @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
139                         @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
140                         @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used to  register for  distribution (PUT,DELETE,POST  will be rejected) - POL4050"),
141                         @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")})
142         public Response getAssetList(
143                         @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
144                         @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
145                         @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
146                         @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
147                         @ApiParam(value = "The requested asset type", required = true, allowableValues = "resources, services")@PathParam("assetType") final String assetType, 
148                         @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("category") String category, 
149                         @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("subCategory") String subCategory, 
150                         @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("distributionStatus") String distributionStatus,
151                         @ApiParam(value = "The filter key (resourceType only for resources)", required = false)@QueryParam("resourceType") String resourceType) {
152
153                 Response response = null;
154                 ResponseFormat responseFormat = null;
155                 String query = request.getQueryString();
156                 String requestURI = request.getRequestURI();
157                 String url = request.getMethod() + " " + requestURI;
158                 log.debug("Start handle request of {}", url);
159                 
160                 AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST;
161
162                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
163                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
164                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, query == null ? requestURI : requestURI + "?" + query);
165
166                 // Mandatory
167                 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
168                         log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
169                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
170                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
171                         return buildErrorResponse(responseFormat);
172                 }
173
174                 try {
175                         ServletContext context = request.getSession().getServletContext();
176                         ElementBusinessLogic elementLogic = getElementBL(context);
177
178                         AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
179                         Map<FilterKeyEnum, String> filters = new HashMap<FilterKeyEnum, String>();
180
181                         if (category != null) {
182                                 filters.put(FilterKeyEnum.CATEGORY, category);
183                         }
184                         if (subCategory != null) {
185                                 filters.put(FilterKeyEnum.SUB_CATEGORY, subCategory);
186                         }
187                         if (distributionStatus != null) {
188                                 filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus);
189                         }
190                         if (resourceType != null) {
191                                 ResourceTypeEnum resourceTypeEnum = ResourceTypeEnum.getTypeIgnoreCase(resourceType);
192                                 if( resourceTypeEnum == null ){
193                                         log.debug("getAssetList: Asset Fetching Failed. Invalid resource type was received");
194                                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
195                                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
196                                         return buildErrorResponse(responseFormat);
197                                 }
198                                 filters.put(FilterKeyEnum.RESOURCE_TYPE, resourceTypeEnum.name());
199                         }
200
201                         Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getFilteredCatalogComponents(assetType, filters, query);
202
203                         if (assetTypeData.isRight()) {
204                                 log.debug("getAssetList: Asset Fetching Failed");
205                                 responseFormat = assetTypeData.right().value();
206                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
207                                 return buildErrorResponse(responseFormat);
208                         } else {
209                                 log.debug("getAssetList: Asset Fetching Success");
210                                 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), requestURI, false);
211                                 if (resMetadata.isRight()) {
212                                         log.debug("getAssetList: Asset conversion Failed");
213                                         responseFormat = resMetadata.right().value();
214                                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
215                                         return buildErrorResponse(responseFormat);
216                                 }
217                                 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value());
218                                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
219                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
220
221                                 response = buildOkResponse(responseFormat, result);
222                                 return response;
223                         }
224                 } catch (Exception e) {
225                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
226                         log.debug("getAssetList: Fetch list of assets failed with exception", e);
227                         return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
228                 }
229         }
230         
231         /**
232          * 
233          * @param assetType
234          * @param uuid
235          * @param request
236          * @param instanceIdHeader
237          * @return
238          */
239         @GET
240         @Path("/{assetType}/{uuid}/metadata")
241         @Produces(MediaType.APPLICATION_JSON)
242         @ApiOperation(value = "Fetch metadata of asset by uuid", httpMethod = "GET", notes = "Returns metadata of asset", response = Response.class)
243         @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
244                         @ApiResponse(code = 404, message = "Asset not found") })
245         public Response getAssetListByUuid(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @Context final HttpServletRequest request,
246                         @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader) {
247
248                 Response response = null;
249                 ResponseFormat responseFormat = null;
250                 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA;
251                 String requestURI = request.getRequestURI();
252                 String url = request.getMethod() + " " + requestURI;
253                 log.debug("Start handle request of {}", url);
254
255                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
256                 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
257                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
258                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI);
259                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
260                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
261
262                 // Mandatory
263                 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
264                         log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
265                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
266                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
267                         return buildErrorResponse(responseFormat);
268                 }
269
270                 try {
271                         ServletContext context = request.getSession().getServletContext();
272                         ElementBusinessLogic elementLogic = getElementBL(context);
273                         AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
274
275                         Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid);
276
277                         if (assetTypeData.isRight()) {
278                                 log.debug("getAssetList: Asset Fetching Failed");
279                                 responseFormat = assetTypeData.right().value();
280                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
281
282                                 return buildErrorResponse(responseFormat);
283                         } else {
284                                 log.debug("getAssetList: Asset Fetching Success");
285                                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, assetTypeData.left().value().iterator().next().getName());
286                                 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), requestURI, true);
287                                 if (resMetadata.isRight()) {
288                                         log.debug("getAssetList: Asset conversion Failed");
289                                         responseFormat = resMetadata.right().value();
290                                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
291                                         return buildErrorResponse(responseFormat);
292                                 }
293                                 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value().iterator().next());
294                                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
295                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
296
297                                 response = buildOkResponse(responseFormat, result);
298                                 return response;
299                         }
300                 } catch (Exception e) {
301                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
302                         log.debug("getAssetList: Fetch list of assets failed with exception", e);
303                         return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
304                 }
305         }
306         
307         /**
308          * 
309          * @param uuid
310          * @param assetType
311          * @param authorization
312          * @param instanceIdHeader
313          * @return
314          */
315         @GET
316         @Path("/{assetType}/{uuid}/toscaModel")
317         @Produces(MediaType.APPLICATION_OCTET_STREAM)
318         @ApiOperation(value = "Fetch asset csar", httpMethod = "GET", notes = "Returns asset csar", response = Response.class)
319         @ApiResponses(value = { @ApiResponse(code = 200, message = "Asset Model Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
320                         @ApiResponse(code = 404, message = "Asset not found") })
321         public Response getToscaModel(@PathParam("uuid") final String uuid,
322                         @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType,
323                         @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization, @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader) {
324
325                 String url = request.getRequestURI();
326                 log.debug("Start handle request of {} {}", request.getMethod(), url);
327                 Response response = null;
328                 ResponseFormat responseFormat = null;
329                 ServletContext context = request.getSession().getServletContext();
330                 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
331                 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_TOSCA_MODEL;
332                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
333                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
334                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, url);
335                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
336                 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
337
338                 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
339                         log.debug("getToscaModel: Missing X-ECOMP-InstanceID header");
340                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
341                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
342                         return buildErrorResponse(responseFormat);
343                 }
344
345                 try {
346                         ComponentBusinessLogic componentBL = getComponentBL(componentType, context);
347
348                         Either<ImmutablePair<String, byte[]>, ResponseFormat> csarArtifact = componentBL.getToscaModelByComponentUuid(componentType, uuid, additionalParam);
349                         if (csarArtifact.isRight()) {
350                                 responseFormat = csarArtifact.right().value();
351                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
352                                 response = buildErrorResponse(responseFormat);
353                         } else {
354                                 byte[] value = csarArtifact.left().value().getRight();
355                                 InputStream is = new ByteArrayInputStream(value);
356                                 String contenetMD5 = GeneralUtility.calculateMD5ByByteArray(value);
357                                 Map<String, String> headers = new HashMap<>();
358                                 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(csarArtifact.left().value().getLeft()));
359                                 headers.put(Constants.MD5_HEADER, contenetMD5);
360                                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
361                                 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
362                                 response = buildOkResponse(responseFormat, is, headers);
363                         }
364                         return response;
365
366                 } catch (Exception e) {
367                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get asset tosca model");
368                         log.debug("falied to get asset tosca model", e);
369                         responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
370                         response = buildErrorResponse(responseFormat);
371                         getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
372                         return response;
373                 }
374         }
375         
376         /**
377          * Creates a new Resource
378          * 
379          * @param assetType
380          * @param data
381          * @param userId
382          * @param instanceIdHeader
383          * @return
384          */
385         @POST
386         @Path("/{assetType}")
387         @Consumes(MediaType.APPLICATION_JSON)
388         @Produces(MediaType.APPLICATION_JSON)
389         @ApiOperation(value = "creates a resource", httpMethod = "POST", notes = "creates a resource", response = Response.class)
390         @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact uploaded"),
391                         @ApiResponse(code = 401, message = "Authorization required"),
392                         @ApiResponse(code = 403, message = "Restricted operation"),
393                         @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
394                         @ApiResponse(code = 409, message = "Resource already exist") })
395         public Response createResource(@PathParam("assetType") final String assetType, 
396                         @ApiParam(value = "json describe the artifact", required = true) String data,
397                         @HeaderParam(value = Constants.USER_ID_HEADER) final String userId, 
398                         @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader) {
399                 
400                 init(log);
401                 
402                 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
403                 String requestURI = request.getRequestURI();
404                 String url = request.getMethod() + " " + requestURI;
405                 log.debug("Start handle request of {}", url);
406                 Resource resource = null;
407                 User modifier = null;
408                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
409                 ServletContext context = request.getSession().getServletContext();
410                 ResourceBusinessLogic resourceBL = getResourceBL(context);
411                 try {
412                         // Validate X-ECOMP-InstanceID Header
413                         if (responseWrapper.isEmpty()) {
414                                 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
415                         }
416                         // Validate USER_ID Header
417                         if (responseWrapper.isEmpty()) {
418                                 validateHttpCspUserIdHeader(userId, responseWrapper);
419                         }
420                         // Validate assetType
421                         if (responseWrapper.isEmpty()) {
422                                 if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) ){
423                                         responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
424                                 }
425                         }
426                         //Validate resource type
427                         if(responseWrapper.isEmpty()){
428                                 JSONParser parser = new JSONParser();
429                                 JSONObject jsonObj = (JSONObject) parser.parse(data);
430                                 String resourceType = (String) jsonObj.get(FilterKeyEnum.RESOURCE_TYPE.getName());
431                                 if( StringUtils.isEmpty(resourceType) || !ResourceTypeEnum.containsName(resourceType) ){
432                                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, (String) jsonObj.get("name"));
433                                         responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
434                                 }
435                         }
436                         // Convert the user json to a resource
437                         if (responseWrapper.isEmpty()) {
438                                 modifier = new User();
439                                 modifier.setUserId(userId);
440                                 Either<Resource, ResponseFormat> eitherResource = getComponentsUtils()
441                                                 .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class,
442                                                                 null, ComponentTypeEnum.RESOURCE);
443                                 if( eitherResource.isRight() ){
444                                         responseWrapper.setInnerElement(eitherResource.right().value());
445                                 }
446                                 else{
447                                         resource = eitherResource.left().value();
448                                 }
449
450                         }
451                         //validate name exist
452                         if(responseWrapper.isEmpty()){
453                                 if( Strings.isEmpty(resource.getName())){
454                                         responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
455                                                         ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()));
456
457                                 }
458                         }
459                         
460                         if(responseWrapper.isEmpty()){
461                                 resource.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
462                                 resource.setSystemName(ValidationUtils.convertToSystemName(resource.getName()));
463                                 resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VFCMT.name(),
464                                                 resource.getSystemName()));
465                                 handleCategories(context, data, resource, responseWrapper);
466                         }
467                         // Create the resource in the dataModel
468                         if (responseWrapper.isEmpty()) {
469                                 Either<Resource, ResponseFormat> eitherCreateResponse = resourceBL.createResource(resource, null,
470                                                 modifier, null, null);
471                                 if (eitherCreateResponse.isRight()) {
472                                         responseWrapper.setInnerElement(eitherCreateResponse.right().value());
473                                 } else {
474                                         resource = eitherCreateResponse.left().value();
475                                 }
476                         }
477                         Response response;
478                         //Build Response and store it in the response Wrapper
479                         if (responseWrapper.isEmpty()) {
480                                 response = buildCreatedResourceResponse(resource, context, responseWrapper);
481                         }
482                         else{
483                                 response = buildErrorResponse(responseWrapper.getInnerElement());
484                         }
485                         return response;
486
487                 } catch (Exception e) {
488                         final String message = "failed to create vfc monitoring template resource";
489                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message);
490                         log.debug(message, e);
491                         return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
492                 }
493                 finally{
494                         prepareAdditionalAudit(resource, additionalParams);
495                         
496                         getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
497                                         ComponentTypeEnum.RESOURCE.getValue(), AuditingActionEnum.CREATE_RESOURCE_BY_API.getName(), request,
498                                         additionalParams);
499                 }
500         }
501         
502         /**
503          * Changing the lifecycle of an asset
504          * @param jsonChangeInfo        The description - request body
505          * @param assetType The requested asset type.Valid values are: resources / services (for VFCMT – use "resources")
506          * @param uuid The uuid of the desired resource to be changed
507          * @param lifecycleTransition The lifecycle operation to be performed on the asset.Valid values are:Checkin / Checkout /  CERTIFICATION_REQUEST
508          * @param userId
509          * @return
510          */
511         @POST
512         @Path("/{assetType}/{uuid}/lifecycleState/{lifecycleOperation}")
513         @Consumes(MediaType.APPLICATION_JSON)
514         @Produces(MediaType.APPLICATION_JSON)
515         @ApiOperation(value = "Change Resource lifecycle State", httpMethod = "POST", response = Response.class)
516         @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource state changed"), @ApiResponse(code = 403, message = "Asset is already checked-out by another user")})
517         public Response changeResourceState(@ApiParam(value = "LifecycleChangeInfo - relevant for checkin", required = false) String jsonChangeInfo,
518                         @ApiParam(value = "validValues: resources / services ", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam(value = "assetType") final String assetType,
519                         @ApiParam(value = "id of component to be changed") @PathParam(value = "uuid") final String uuid,
520                         @ApiParam(allowableValues = "checkout, checkin", required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition, 
521                         @HeaderParam(value = Constants.USER_ID_HEADER) final String userId) {
522                 
523                 Response response = null;
524                 EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
525                 
526                 init(log);
527                 
528                 String requestURI = request.getRequestURI();
529                 String url = request.getMethod() + " " + requestURI;
530                 log.debug("Start handle request of {}", url);
531                 
532                 //get the business logic
533                 ServletContext context = request.getSession().getServletContext();
534                 LifecycleBusinessLogic businessLogic = getLifecycleBL(context);         
535                 
536                 Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);                                    
537                 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
538                 Component component = null;
539                 Component responseObject = null;
540                 User modifier = null;
541                 
542                 try{
543                         if (responseWrapper.isEmpty()) {
544                                 //get user
545                                 Either<User, ResponseFormat> eitherGetUser = getUser(request, userId);
546                                 if (eitherGetUser.isRight()) {
547                                         ResponseFormat responseFormat = eitherGetUser.right().value();
548                                         responseWrapper.setInnerElement(responseFormat);
549                                         return buildErrorResponse(responseFormat);
550                                 }
551                                 modifier = eitherGetUser.left().value();
552                                                                 
553                                 //get the component id from the uuid
554                                 Either<Component, ResponseFormat> latestVersion = businessLogic.getLatestComponentByUuid(componentType, uuid);          
555                                 if (latestVersion.isRight()) {
556                                         ResponseFormat responseFormat = latestVersion.right().value();
557                                         responseWrapper.setInnerElement(responseFormat);
558                                         return buildErrorResponse(responseFormat);
559                                 }
560                                 component = latestVersion.left().value();
561                                 String componentId = component.getUniqueId();
562                                                                 
563                                 //validate the transition is valid
564                                 Either<LifeCycleTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(lifecycleTransition, modifier);
565                                 if (validateEnum.isRight()) {
566                                         ResponseFormat responseFormat = validateEnum.right().value();
567                                         responseWrapper.setInnerElement(responseFormat);
568                                         return buildErrorResponse(responseFormat);
569                                 }
570                                 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
571                                 
572                                 //create changeInfo
573                                 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
574                                 try {
575                                         if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
576                                                 ObjectMapper mapper = new ObjectMapper();
577                                                 changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
578                                         }
579                                 }
580                                 catch (Exception e) {
581                                         BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject");
582                                         BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
583                                         log.debug("failed to convert from json {}", jsonChangeInfo, e);
584                                         ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(modifier, AuditingActionEnum.CHECKOUT_RESOURCE);
585                                         responseWrapper.setInnerElement(responseFormat);
586                                         return buildErrorResponse(responseFormat);
587                                 }
588                                 
589                                 //execute business logic
590                                 Either<? extends Component, ResponseFormat> actionResponse = businessLogic.changeComponentState(componentType, componentId, modifier, transitionEnum, changeInfo, false, true); 
591                                 if (actionResponse.isRight()) {
592                                         log.info("failed to change resource state");
593                                         ResponseFormat responseFormat = actionResponse.right().value();
594                                         responseWrapper.setInnerElement(responseFormat);
595                                         return buildErrorResponse(responseFormat);                                      
596                                 }
597           
598                                 log.debug("change state successful !!!");
599                                 responseObject = actionResponse.left().value();
600                                 response = buildCreatedResourceResponse(responseObject, context, responseWrapper);                              
601                         } else {
602                                 response = buildErrorResponse(responseWrapper.getInnerElement());
603                         }
604                         
605                         return response;
606                 } catch (Exception e) {
607                         BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Change Lifecycle State");
608                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State");
609                         log.debug("change lifecycle state failed with exception", e);
610                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
611                         responseWrapper.setInnerElement(responseFormat);
612                         return buildErrorResponse(responseFormat);                      
613                 } finally{
614                         auditChnageLifecycleAction(additionalParams, responseWrapper, componentType, component, responseObject, modifier, userId);
615                 }
616         }
617         
618         private void prepareAdditionalAudit(Resource resource, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) {
619                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, StringUtils.EMPTY);            
620                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, StringUtils.EMPTY);
621                 
622                 if( resource != null ){
623                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, ImportUtils.Constants.FIRST_NON_CERTIFIED_VERSION);
624                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name());
625                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resource.getName());
626                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, resource.getUUID());
627                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, resource.getInvariantUUID());
628                 } else {
629                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, StringUtils.EMPTY);
630                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, StringUtils.EMPTY);
631                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, StringUtils.EMPTY);
632                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, StringUtils.EMPTY);
633                 }
634         }
635
636         private Response buildCreatedResourceResponse(Component resource, ServletContext context,
637                         Wrapper<ResponseFormat> responseWrapper) throws IOException, JsonGenerationException, JsonMappingException {
638                 ResponseFormat responseFormat;
639                 Response response;
640                 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
641                 Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
642                                 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(),
643                                                 true);
644                 if (resMetadata.isRight()) {
645                         log.debug("Asset conversion Failed");
646                         responseFormat = resMetadata.right().value();
647                         responseWrapper.setInnerElement(responseFormat);
648                         response = buildErrorResponse(responseFormat);
649                 }else{
650                         final AssetMetadata assetData = resMetadata.left().value();
651                         assetData.setToscaModelURL(null);
652                         
653                         responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
654                         Object representation = RepresentationUtils.toRepresentation(assetData);
655                         response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
656                 }
657                 return response;
658         }
659
660         private void handleCategories(ServletContext context, String data, Resource resource,
661                         Wrapper<ResponseFormat> responseWrapper) {
662                 try {
663                         JSONParser parser = new JSONParser();
664                         JSONObject jsonObj = (JSONObject) parser.parse(data);
665                         String category = (String) jsonObj.get(CategoryTypeEnum.CATEGORY.getValue());
666                         String subcategory = (String) jsonObj.get(CategoryTypeEnum.SUBCATEGORY.getValue());
667                         if (Strings.isEmpty(category)) {
668                                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
669                                                 ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
670                         }
671                         else if (Strings.isEmpty(subcategory)) {
672                                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
673                                                 ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
674                         }
675                         if (responseWrapper.isEmpty()) {
676                                 ElementBusinessLogic elementLogic = getElementBL(context);
677                                 // get All Categories
678                                 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories = elementLogic
679                                                 .getAllResourceCategories();
680                                 // Error fetching categories
681                                 if (allResourceCategories.isRight()) {
682                                         responseWrapper.setInnerElement(
683                                                         getComponentsUtils().getResponseFormat(allResourceCategories.right().value()));
684                                 } else {
685                                         addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
686                                 }
687                         }
688                 } catch (Exception e) {
689                         log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
690                         responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
691                 }
692
693         }
694
695         private void addCategories(Resource resource, String category, String subcategory,
696                         Either<List<CategoryDefinition>, ActionStatus> allResourceCategories,
697                         Wrapper<ResponseFormat> responseWrapper) {
698                 Optional<CategoryDefinition> optionalCategory =
699                                 // Stream of all the categories
700                                 allResourceCategories.left().value().stream()
701                                                 // filter in only relevant category
702                                                 .filter(e -> e.getName().equals(category))
703                                                 // get the result
704                                                 .findAny();
705                 if (!optionalCategory.isPresent()) {
706                         responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
707                                         ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
708                 } else {
709                         CategoryDefinition categoryDefinition = optionalCategory.get();
710
711                         List<SubCategoryDefinition> subCaregories =
712                                         // Stream of all sub-categories of the relevant
713                                         // category
714                                         categoryDefinition.getSubcategories().stream()
715                                                         // filter in only relevant sub-category
716                                                         .filter(e -> e.getName().equals(subcategory))
717                                                         // get the result
718                                                         .collect(Collectors.toList());
719                         
720                         if( subCaregories.isEmpty() ){
721                                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
722                                                 ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
723                         }
724                         else{
725                                 categoryDefinition.setSubcategories(subCaregories);
726                                 resource.setCategories(Arrays.asList(categoryDefinition));
727                         }
728                         
729                 }
730         }
731
732         
733         
734
735         private void auditChnageLifecycleAction(EnumMap<AuditingFieldsKeysEnum, Object> additionalParams,
736                         Wrapper<ResponseFormat> responseWrapper, ComponentTypeEnum componentType, Component component,
737                         Component responseObject, User modifier, String userId) {
738                 if (modifier!=null){
739                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFullName());
740                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId());
741                 } else {
742                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, "");
743                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, userId);
744                 }
745                 
746                 if (component!=null){
747                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, component.getName());
748                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, component.getVersion());
749                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, component.getLifecycleState().name());
750                 } else {
751                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, "");
752                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, "");
753                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, "");
754                 }
755                 
756                 if (responseObject!=null){
757                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, responseObject.getVersion());
758                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, responseObject.getUUID());
759                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, responseObject.getInvariantUUID());
760                         additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,responseObject.getLifecycleState().name());
761                 } else {
762                         if (component!=null){
763                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, component.getVersion());
764                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, component.getUUID());
765                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, component.getInvariantUUID());
766                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,component.getLifecycleState().name());
767                         } else {
768                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, "");
769                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, "");
770                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, "");
771                                 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,"");
772                         }
773                 }
774                 
775                 getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
776                                 componentType.getValue(), AuditingActionEnum.CHANGE_LIFECYCLE_BY_API.getName(), request,
777                                 additionalParams);
778         }
779
780         private Wrapper<ResponseFormat> runValidations(final String assetType) {
781                 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
782                 
783                 // Validate X-ECOMP-InstanceID Header
784                 if (responseWrapper.isEmpty()) {
785                         String instanceId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
786                         validateXECOMPInstanceIDHeader(instanceId,responseWrapper);                     
787                 }
788                 // Validate USER_ID Header
789                 if (responseWrapper.isEmpty()) {
790                         validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER),responseWrapper);
791                 }
792                 // Validate assetType
793                 if (responseWrapper.isEmpty()) {
794                         if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) &&  !AssetTypeEnum.SERVICES.getValue().equals(assetType)){
795                                 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
796                         }
797                 }
798                 
799                 return responseWrapper;
800         }
801         
802         private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
803                 LifeCycleTransitionEnum transitionEnum = LifeCycleTransitionEnum.CHECKOUT;
804                 try {
805                         transitionEnum = LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition);
806                 } catch (IllegalArgumentException e) {
807                         log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString());
808                         ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, AuditingActionEnum.CHECKOUT_RESOURCE);
809                         return Either.right(error);
810                 }
811                 return Either.left(transitionEnum);
812         }
813         
814 }