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