2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.be.externalapi.servlet;
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;
31 import java.util.Optional;
32 import java.util.stream.Collectors;
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;
49 import org.apache.commons.lang3.StringUtils;
50 import org.apache.commons.lang3.tuple.ImmutablePair;
51 import org.codehaus.jackson.JsonGenerationException;
52 import org.codehaus.jackson.map.JsonMappingException;
53 import org.codehaus.jackson.map.ObjectMapper;
54 import org.elasticsearch.common.Strings;
55 import org.json.simple.JSONObject;
56 import org.json.simple.parser.JSONParser;
57 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
58 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
59 import org.openecomp.sdc.be.components.impl.ImportUtils;
60 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
61 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
62 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase;
63 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
64 import org.openecomp.sdc.be.config.BeEcompErrorManager;
65 import org.openecomp.sdc.be.dao.api.ActionStatus;
66 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
67 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
68 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
69 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
70 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
71 import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
72 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
73 import org.openecomp.sdc.be.model.Component;
74 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
75 import org.openecomp.sdc.be.model.LifecycleStateEnum;
76 import org.openecomp.sdc.be.model.Resource;
77 import org.openecomp.sdc.be.model.User;
78 import org.openecomp.sdc.be.model.category.CategoryDefinition;
79 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
80 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
81 import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
82 import org.openecomp.sdc.be.servlets.RepresentationUtils;
83 import org.openecomp.sdc.be.utils.CommonBeUtils;
84 import org.openecomp.sdc.common.api.Constants;
85 import org.openecomp.sdc.common.config.EcompErrorName;
86 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
87 import org.openecomp.sdc.common.datastructure.Wrapper;
88 import org.openecomp.sdc.common.util.GeneralUtility;
89 import org.openecomp.sdc.common.util.ValidationUtils;
90 import org.openecomp.sdc.exception.ResponseFormat;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
94 import com.jcabi.aspects.Loggable;
95 import com.wordnik.swagger.annotations.Api;
96 import com.wordnik.swagger.annotations.ApiOperation;
97 import com.wordnik.swagger.annotations.ApiParam;
98 import com.wordnik.swagger.annotations.ApiResponse;
99 import com.wordnik.swagger.annotations.ApiResponses;
101 import fj.data.Either;
104 * This Servlet serves external users for retrieving component metadata.
110 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
112 @Api(value = "Asset Metadata External Servlet", description = "This Servlet serves external users for retrieving component metadata.")
114 public class AssetsDataServlet extends AbstractValidationsServlet {
117 private HttpServletRequest request;
119 private static Logger log = LoggerFactory.getLogger(AssetsDataServlet.class.getName());
122 @Path("/{assetType}")
123 @Produces(MediaType.APPLICATION_JSON)
124 @ApiOperation(value = "Fetch list of assets", httpMethod = "GET", notes = "Returns list of assets", response = Response.class)
125 @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), @ApiResponse(code = 401, message = "Authorization required"),
126 @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Asset not found") })
127 public Response getAssetList(@PathParam("assetType") final String assetType, @QueryParam("category") String category, @QueryParam("subCategory") String subCategory, @QueryParam("distributionStatus") String distributionStatus,
128 @QueryParam("resourceType") String resourceType) {
130 Response response = null;
131 ResponseFormat responseFormat = null;
132 String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
133 String query = request.getQueryString();
134 String requestURI = request.getRequestURI();
135 String url = request.getMethod() + " " + requestURI;
136 log.debug("Start handle request of {}", url);
138 AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST;
140 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
141 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
142 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, query == null ? requestURI : requestURI + "?" + query);
145 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
146 log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
147 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
148 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
149 return buildErrorResponse(responseFormat);
153 ServletContext context = request.getSession().getServletContext();
154 ElementBusinessLogic elementLogic = getElementBL(context);
156 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
157 Map<FilterKeyEnum, String> filters = new HashMap<FilterKeyEnum, String>();
159 if (category != null) {
160 filters.put(FilterKeyEnum.CATEGORY, category);
162 if (subCategory != null) {
163 filters.put(FilterKeyEnum.SUB_CATEGORY, subCategory);
165 if (distributionStatus != null) {
166 filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus);
168 if (resourceType != null) {
169 ResourceTypeEnum resourceTypeEnum = ResourceTypeEnum.getTypeIgnoreCase(resourceType);
170 if( resourceTypeEnum == null ){
171 log.debug("getAssetList: Asset Fetching Failed. Invalid resource type was received");
172 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
173 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
174 return buildErrorResponse(responseFormat);
176 filters.put(FilterKeyEnum.RESOURCE_TYPE, resourceTypeEnum.name());
179 Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getFilteredCatalogComponents(assetType, filters, query);
181 if (assetTypeData.isRight()) {
182 log.debug("getAssetList: Asset Fetching Failed");
183 responseFormat = assetTypeData.right().value();
184 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
185 return buildErrorResponse(responseFormat);
187 log.debug("getAssetList: Asset Fetching Success");
188 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), requestURI, false);
189 if (resMetadata.isRight()) {
190 log.debug("getAssetList: Asset conversion Failed");
191 responseFormat = resMetadata.right().value();
192 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
193 return buildErrorResponse(responseFormat);
195 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value());
196 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
197 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
199 response = buildOkResponse(responseFormat, result);
202 } catch (Exception e) {
203 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
204 log.debug("getAssetList: Fetch list of assets failed with exception", e);
205 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
210 @Path("/{assetType}/{uuid}/metadata")
211 @Produces(MediaType.APPLICATION_JSON)
212 @ApiOperation(value = "Fetch metadata of asset by uuid", httpMethod = "GET", notes = "Returns metadata of asset", response = Response.class)
213 @ApiResponses(value = { @ApiResponse(code = 200, message = "Assets Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
214 @ApiResponse(code = 404, message = "Asset not found") })
215 public Response getAssetListByUuid(@PathParam("assetType") final String assetType, @PathParam("uuid") final String uuid, @Context final HttpServletRequest request) {
217 Response response = null;
218 ResponseFormat responseFormat = null;
219 String instanceIdHeader = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
220 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_ASSET_METADATA;
221 String requestURI = request.getRequestURI();
222 String url = request.getMethod() + " " + requestURI;
223 log.debug("Start handle request of {}", url);
225 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
226 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
227 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, instanceIdHeader);
228 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, requestURI);
229 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
230 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
233 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
234 log.debug("getAssetList: Missing X-ECOMP-InstanceID header");
235 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
236 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
237 return buildErrorResponse(responseFormat);
241 ServletContext context = request.getSession().getServletContext();
242 ElementBusinessLogic elementLogic = getElementBL(context);
243 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
245 Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid);
247 if (assetTypeData.isRight()) {
248 log.debug("getAssetList: Asset Fetching Failed");
249 responseFormat = assetTypeData.right().value();
250 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
252 return buildErrorResponse(responseFormat);
254 log.debug("getAssetList: Asset Fetching Success");
255 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, assetTypeData.left().value().iterator().next().getName());
256 Either<List<? extends AssetMetadata>, ResponseFormat> resMetadata = assetMetadataUtils.convertToAssetMetadata(assetTypeData.left().value(), requestURI, true);
257 if (resMetadata.isRight()) {
258 log.debug("getAssetList: Asset conversion Failed");
259 responseFormat = resMetadata.right().value();
260 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
261 return buildErrorResponse(responseFormat);
263 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value().iterator().next());
264 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
265 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
267 response = buildOkResponse(responseFormat, result);
270 } catch (Exception e) {
271 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Fetch filtered list of assets");
272 log.debug("getAssetList: Fetch list of assets failed with exception", e);
273 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
278 @Path("/{assetType}/{uuid}/toscaModel")
279 @Produces(MediaType.APPLICATION_OCTET_STREAM)
280 @ApiOperation(value = "Fetch asset csar", httpMethod = "GET", notes = "Returns asset csar", response = Response.class)
281 @ApiResponses(value = { @ApiResponse(code = 200, message = "Asset Model Fetched"), @ApiResponse(code = 401, message = "Authorization required"), @ApiResponse(code = 403, message = "Restricted operation"),
282 @ApiResponse(code = 404, message = "Asset not found") })
283 public Response getToscaModel(@PathParam("uuid") final String uuid,
284 @ApiParam(value = "valid values: resources / services", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam("assetType") final String assetType,
285 @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization) {
287 String url = request.getRequestURI();
288 log.debug("Start handle request of {} {}", request.getMethod(), url);
289 Response response = null;
290 ResponseFormat responseFormat = null;
291 ServletContext context = request.getSession().getServletContext();
292 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
293 AuditingActionEnum auditingActionEnum = AuditingActionEnum.GET_TOSCA_MODEL;
294 String userId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
295 EnumMap<AuditingFieldsKeysEnum, Object> additionalParam = new EnumMap<AuditingFieldsKeysEnum, Object>(AuditingFieldsKeysEnum.class);
296 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_CONSUMER_ID, userId);
297 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, url);
298 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, componentType.getValue());
299 additionalParam.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, uuid);
301 if (userId == null || userId.isEmpty()) {
302 log.debug("getToscaModel: Missing X-ECOMP-InstanceID header");
303 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
304 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
305 return buildErrorResponse(responseFormat);
309 ComponentBusinessLogic componentBL = getComponentBL(componentType, context);
311 Either<ImmutablePair<String, byte[]>, ResponseFormat> csarArtifact = componentBL.getToscaModelByComponentUuid(componentType, uuid, additionalParam);
312 if (csarArtifact.isRight()) {
313 responseFormat = csarArtifact.right().value();
314 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
315 response = buildErrorResponse(responseFormat);
317 byte[] value = csarArtifact.left().value().getRight();
318 InputStream is = new ByteArrayInputStream(value);
319 String contenetMD5 = GeneralUtility.calculateMD5ByByteArray(value);
320 Map<String, String> headers = new HashMap<>();
321 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(csarArtifact.left().value().getLeft()));
322 headers.put(Constants.MD5_HEADER, contenetMD5);
323 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
324 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
325 response = buildOkResponse(responseFormat, is, headers);
329 } catch (Exception e) {
330 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get asset tosca model");
331 log.debug("falied to get asset tosca model", e);
332 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
333 response = buildErrorResponse(responseFormat);
334 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
340 * Creates a new Resource
347 @Path("/{assetType}")
348 @Consumes(MediaType.APPLICATION_JSON)
349 @Produces(MediaType.APPLICATION_JSON)
350 @ApiOperation(value = "creates a resource", httpMethod = "POST", notes = "creates a resource", response = Response.class)
351 @ApiResponses(value = { @ApiResponse(code = 200, message = "Artifact uploaded"),
352 @ApiResponse(code = 401, message = "Authorization required"),
353 @ApiResponse(code = 403, message = "Restricted operation"),
354 @ApiResponse(code = 201, message = "Resource created"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
355 @ApiResponse(code = 409, message = "Resource already exist") })
356 public Response createResource(@PathParam("assetType") final String assetType, @ApiParam(value = "json describe the artifact", required = true) String data) {
359 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
360 String requestURI = request.getRequestURI();
361 String userId = request.getHeader(Constants.USER_ID_HEADER);
362 String url = request.getMethod() + " " + requestURI;
363 log.debug("Start handle request of {}", url);
364 Resource resource = null;
365 User modifier = null;
366 EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
367 ServletContext context = request.getSession().getServletContext();
368 ResourceBusinessLogic resourceBL = getResourceBL(context);
370 // Validate X-ECOMP-InstanceID Header
371 if (responseWrapper.isEmpty()) {
372 validateXECOMPInstanceIDHeader(request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER),
375 // Validate USER_ID Header
376 if (responseWrapper.isEmpty()) {
377 validateHttpCspUserIdHeader(userId, responseWrapper);
379 // Validate assetType
380 if (responseWrapper.isEmpty()) {
381 if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) ){
382 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
385 //Validate resource type
386 if(responseWrapper.isEmpty()){
387 JSONParser parser = new JSONParser();
388 JSONObject jsonObj = (JSONObject) parser.parse(data);
389 String resourceType = (String) jsonObj.get(FilterKeyEnum.RESOURCE_TYPE.getName());
390 if( StringUtils.isEmpty(resourceType) || !ResourceTypeEnum.containsName(resourceType) ){
391 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, (String) jsonObj.get("name"));
392 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
395 // Convert the user json to a resource
396 if (responseWrapper.isEmpty()) {
397 modifier = new User();
398 modifier.setUserId(userId);
399 Either<Resource, ResponseFormat> eitherResource = getComponentsUtils()
400 .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class,
401 null, ComponentTypeEnum.RESOURCE);
402 if( eitherResource.isRight() ){
403 responseWrapper.setInnerElement(eitherResource.right().value());
406 resource = eitherResource.left().value();
410 //validate name exist
411 if(responseWrapper.isEmpty()){
412 if( Strings.isEmpty(resource.getName())){
413 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
414 ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()));
419 if(responseWrapper.isEmpty()){
420 resource.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
421 resource.setSystemName(ValidationUtils.convertToSystemName(resource.getName()));
422 resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VFCMT.name(),
423 resource.getSystemName()));
424 handleCategories(context, data, resource, responseWrapper);
426 // Create the resource in the dataModel
427 if (responseWrapper.isEmpty()) {
428 Either<Resource, ResponseFormat> eitherCreateResponse = resourceBL.createResource(resource, null,
429 modifier, null, null);
430 if (eitherCreateResponse.isRight()) {
431 responseWrapper.setInnerElement(eitherCreateResponse.right().value());
433 resource = eitherCreateResponse.left().value();
437 //Build Response and store it in the response Wrapper
438 if (responseWrapper.isEmpty()) {
439 response = buildCreatedResourceResponse(resource, context, responseWrapper);
442 response = buildErrorResponse(responseWrapper.getInnerElement());
446 } catch (Exception e) {
447 final String message = "failed to create vfc monitoring template resource";
448 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message);
449 log.debug(message, e);
450 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
453 prepareAdditionalAudit(resource, additionalParams);
455 getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
456 ComponentTypeEnum.RESOURCE.getValue(), AuditingActionEnum.CREATE_RESOURCE_BY_API.getName(), request,
461 private void prepareAdditionalAudit(Resource resource, EnumMap<AuditingFieldsKeysEnum, Object> additionalParams) {
462 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, StringUtils.EMPTY);
463 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, StringUtils.EMPTY);
465 if( resource != null ){
466 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, ImportUtils.Constants.FIRST_NON_CERTIFIED_VERSION);
467 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name());
468 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resource.getName());
469 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, resource.getUUID());
470 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, resource.getInvariantUUID());
472 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, StringUtils.EMPTY);
473 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, StringUtils.EMPTY);
474 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, StringUtils.EMPTY);
475 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, StringUtils.EMPTY);
479 private Response buildCreatedResourceResponse(Component resource, ServletContext context,
480 Wrapper<ResponseFormat> responseWrapper) throws IOException, JsonGenerationException, JsonMappingException {
481 ResponseFormat responseFormat;
483 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
484 Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
485 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(),
487 if (resMetadata.isRight()) {
488 log.debug("Asset conversion Failed");
489 responseFormat = resMetadata.right().value();
490 responseWrapper.setInnerElement(responseFormat);
491 response = buildErrorResponse(responseFormat);
494 final AssetMetadata assetData = resMetadata.left().value();
495 assetData.setToscaModelURL(null);
497 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
498 Object representation = RepresentationUtils.toRepresentation(assetData);
499 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
500 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
505 private void handleCategories(ServletContext context, String data, Resource resource,
506 Wrapper<ResponseFormat> responseWrapper) {
508 JSONParser parser = new JSONParser();
509 JSONObject jsonObj = (JSONObject) parser.parse(data);
510 String category = (String) jsonObj.get(CategoryTypeEnum.CATEGORY.getValue());
511 String subcategory = (String) jsonObj.get(CategoryTypeEnum.SUBCATEGORY.getValue());
512 if (Strings.isEmpty(category)) {
513 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
514 ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
516 else if (Strings.isEmpty(subcategory)) {
517 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
518 ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
520 if (responseWrapper.isEmpty()) {
521 ElementBusinessLogic elementLogic = getElementBL(context);
522 // get All Categories
523 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories = elementLogic
524 .getAllResourceCategories();
525 // Error fetching categories
526 if (allResourceCategories.isRight()) {
527 responseWrapper.setInnerElement(
528 getComponentsUtils().getResponseFormat(allResourceCategories.right().value()));
530 addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
533 } catch (Exception e) {
534 log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
535 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
540 private void addCategories(Resource resource, String category, String subcategory,
541 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories,
542 Wrapper<ResponseFormat> responseWrapper) {
543 Optional<CategoryDefinition> optionalCategory =
544 // Stream of all the categories
545 allResourceCategories.left().value().stream()
546 // filter in only relevant category
547 .filter(e -> e.getName().equals(category))
550 if (!optionalCategory.isPresent()) {
551 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
552 ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
554 CategoryDefinition categoryDefinition = optionalCategory.get();
556 List<SubCategoryDefinition> subCaregories =
557 // Stream of all sub-categories of the relevant
559 categoryDefinition.getSubcategories().stream()
560 // filter in only relevant sub-category
561 .filter(e -> e.getName().equals(subcategory))
563 .collect(Collectors.toList());
565 if( subCaregories.isEmpty() ){
566 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
567 ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
570 categoryDefinition.setSubcategories(subCaregories);
571 resource.setCategories(Arrays.asList(categoryDefinition));
579 * Changing the lifecycle of an asset
580 * @param jsonChangeInfo The description - request body
581 * @param assetType The requested asset type.Valid values are: resources / services (for VFCMT – use "resources")
582 * @param uuid The uuid of the desired resource to be changed
583 * @param lifecycleTransition The lifecycle operation to be performed on the asset.Valid values are:Checkin / Checkout / CERTIFICATION_REQUEST
587 @Path("/{assetType}/{uuid}/lifecycleState/{lifecycleOperation}")
588 @Consumes(MediaType.APPLICATION_JSON)
589 @Produces(MediaType.APPLICATION_JSON)
590 @ApiOperation(value = "Change Resource lifecycle State", httpMethod = "POST", response = Response.class)
591 @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource state changed"), @ApiResponse(code = 403, message = "Asset is already checked-out by another user")})
592 public Response changeResourceState(@ApiParam(value = "LifecycleChangeInfo - relevant for checkin", required = false) String jsonChangeInfo,
593 @ApiParam(value = "validValues: resources / services ", allowableValues = ComponentTypeEnum.RESOURCE_PARAM_NAME + "," + ComponentTypeEnum.SERVICE_PARAM_NAME) @PathParam(value = "assetType") final String assetType,
594 @ApiParam(value = "id of component to be changed") @PathParam(value = "uuid") final String uuid,
595 @ApiParam(allowableValues = "checkout, checkin", required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition) {
596 Response response = null;
597 EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
601 String requestURI = request.getRequestURI();
602 String url = request.getMethod() + " " + requestURI;
603 log.debug("Start handle request of {}", url);
605 //get the business logic
606 ServletContext context = request.getSession().getServletContext();
607 LifecycleBusinessLogic businessLogic = getLifecycleBL(context);
609 Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);
610 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
611 Component component = null;
612 Component responseObject = null;
613 User modifier = null;
614 String userId = request.getHeader(Constants.USER_ID_HEADER);
617 if (responseWrapper.isEmpty()) {
619 Either<User, ResponseFormat> eitherGetUser = getUser(request, userId);
620 if (eitherGetUser.isRight()) {
621 ResponseFormat responseFormat = eitherGetUser.right().value();
622 responseWrapper.setInnerElement(responseFormat);
623 return buildErrorResponse(responseFormat);
625 modifier = eitherGetUser.left().value();
627 //get the component id from the uuid
628 Either<Component, ResponseFormat> latestVersion = businessLogic.getLatestComponentByUuid(componentType, uuid);
629 if (latestVersion.isRight()) {
630 ResponseFormat responseFormat = latestVersion.right().value();
631 responseWrapper.setInnerElement(responseFormat);
632 return buildErrorResponse(responseFormat);
634 component = latestVersion.left().value();
635 String componentId = component.getUniqueId();
637 //validate the transition is valid
638 Either<LifeCycleTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(lifecycleTransition, modifier);
639 if (validateEnum.isRight()) {
640 ResponseFormat responseFormat = validateEnum.right().value();
641 responseWrapper.setInnerElement(responseFormat);
642 return buildErrorResponse(responseFormat);
644 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
647 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
649 if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
650 ObjectMapper mapper = new ObjectMapper();
651 changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
654 catch (Exception e) {
655 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeInvalidJsonInput, "convertJsonToObject");
656 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
657 log.debug("failed to convert from json {}", jsonChangeInfo, e);
658 ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(modifier, AuditingActionEnum.CHECKOUT_RESOURCE);
659 responseWrapper.setInnerElement(responseFormat);
660 return buildErrorResponse(responseFormat);
663 //execute business logic
664 Either<? extends Component, ResponseFormat> actionResponse = businessLogic.changeComponentState(componentType, componentId, modifier, transitionEnum, changeInfo, false, true);
665 if (actionResponse.isRight()) {
666 log.info("failed to change resource state");
667 ResponseFormat responseFormat = actionResponse.right().value();
668 responseWrapper.setInnerElement(responseFormat);
669 return buildErrorResponse(responseFormat);
672 log.debug("change state successful !!!");
673 responseObject = actionResponse.left().value();
674 response = buildCreatedResourceResponse(responseObject, context, responseWrapper);
676 response = buildErrorResponse(responseWrapper.getInnerElement());
680 } catch (Exception e) {
681 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Change Lifecycle State");
682 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State");
683 log.debug("change lifecycle state failed with exception", e);
684 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
685 responseWrapper.setInnerElement(responseFormat);
686 return buildErrorResponse(responseFormat);
688 auditChnageLifecycleAction(additionalParams, responseWrapper, componentType, component, responseObject, modifier, userId);
692 private void auditChnageLifecycleAction(EnumMap<AuditingFieldsKeysEnum, Object> additionalParams,
693 Wrapper<ResponseFormat> responseWrapper, ComponentTypeEnum componentType, Component component,
694 Component responseObject, User modifier, String userId) {
696 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFullName());
697 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId());
699 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, "");
700 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, userId);
703 if (component!=null){
704 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, component.getName());
705 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, component.getVersion());
706 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, component.getLifecycleState().name());
708 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, "");
709 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, "");
710 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, "");
713 if (responseObject!=null){
714 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, responseObject.getVersion());
715 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, responseObject.getUUID());
716 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, responseObject.getInvariantUUID());
717 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,responseObject.getLifecycleState().name());
719 if (component!=null){
720 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, component.getVersion());
721 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, component.getUUID());
722 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, component.getInvariantUUID());
723 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,component.getLifecycleState().name());
725 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, "");
726 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_SERVICE_INSTANCE_ID, "");
727 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, "");
728 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE,"");
732 getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
733 componentType.getValue(), AuditingActionEnum.CHANGE_LIFECYCLE_BY_API.getName(), request,
737 private Wrapper<ResponseFormat> runValidations(final String assetType) {
738 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
740 // Validate X-ECOMP-InstanceID Header
741 if (responseWrapper.isEmpty()) {
742 String instanceId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
743 validateXECOMPInstanceIDHeader(instanceId,responseWrapper);
745 // Validate USER_ID Header
746 if (responseWrapper.isEmpty()) {
747 validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER),responseWrapper);
749 // Validate assetType
750 if (responseWrapper.isEmpty()) {
751 if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) && !AssetTypeEnum.SERVICES.getValue().equals(assetType)){
752 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
756 return responseWrapper;
760 private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
761 LifeCycleTransitionEnum transitionEnum = LifeCycleTransitionEnum.CHECKOUT;
763 transitionEnum = LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition);
764 } catch (IllegalArgumentException e) {
765 log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString());
766 ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, AuditingActionEnum.CHECKOUT_RESOURCE);
767 return Either.right(error);
769 return Either.left(transitionEnum);