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