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