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.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;
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;
102 import fj.data.Either;
105 * This Servlet serves external users for retrieving component metadata.
111 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
113 @Api(value = "Asset Metadata External Servlet", description = "This Servlet serves external users for retrieving component metadata.")
115 public class AssetsDataServlet extends AbstractValidationsServlet {
118 private HttpServletRequest request;
120 private static Logger log = LoggerFactory.getLogger(AssetsDataServlet.class.getName());
127 * @param distributionStatus
128 * @param resourceType
129 * @param instanceIdHeader
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) {
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);
161 AuditingActionEnum auditingActionEnum = query == null ? AuditingActionEnum.GET_ASSET_LIST : AuditingActionEnum.GET_FILTERED_ASSET_LIST;
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);
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);
176 ServletContext context = request.getSession().getServletContext();
177 ElementBusinessLogic elementLogic = getElementBL(context);
179 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
180 Map<FilterKeyEnum, String> filters = new HashMap<FilterKeyEnum, String>();
182 if (category != null) {
183 filters.put(FilterKeyEnum.CATEGORY, category);
185 if (subCategory != null) {
186 filters.put(FilterKeyEnum.SUB_CATEGORY, subCategory);
188 if (distributionStatus != null) {
189 filters.put(FilterKeyEnum.DISTRIBUTION_STATUS, distributionStatus);
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);
199 filters.put(FilterKeyEnum.RESOURCE_TYPE, resourceTypeEnum.name());
202 Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getFilteredCatalogComponents(assetType, filters, query);
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);
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);
218 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value());
219 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
220 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
222 response = buildOkResponse(responseFormat, result);
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));
237 * @param instanceIdHeader
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) {
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);
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);
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);
272 ServletContext context = request.getSession().getServletContext();
273 ElementBusinessLogic elementLogic = getElementBL(context);
274 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
276 Either<List<? extends Component>, ResponseFormat> assetTypeData = elementLogic.getCatalogComponentsByUuidAndAssetType(assetType, uuid);
278 if (assetTypeData.isRight()) {
279 log.debug("getAssetList: Asset Fetching Failed");
280 responseFormat = assetTypeData.right().value();
281 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
283 return buildErrorResponse(responseFormat);
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);
294 Object result = RepresentationUtils.toRepresentation(resMetadata.left().value().iterator().next());
295 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
296 getComponentsUtils().auditExternalGetAsset(responseFormat, auditingActionEnum, additionalParam);
298 response = buildOkResponse(responseFormat, result);
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));
312 * @param authorization
313 * @param instanceIdHeader
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) {
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);
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);
347 ComponentBusinessLogic componentBL = getComponentBL(componentType, context);
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);
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);
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);
378 * Creates a new Resource
383 * @param instanceIdHeader
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) {
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);
413 // Validate X-ECOMP-InstanceID Header
414 if (responseWrapper.isEmpty()) {
415 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
417 // Validate USER_ID Header
418 if (responseWrapper.isEmpty()) {
419 validateHttpCspUserIdHeader(userId, responseWrapper);
421 // Validate assetType
422 if (responseWrapper.isEmpty()) {
423 if( !AssetTypeEnum.RESOURCES.getValue().equals(assetType) ){
424 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
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));
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());
448 resource = eitherResource.left().value();
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()));
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);
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());
475 resource = eitherCreateResponse.left().value();
479 //Build Response and store it in the response Wrapper
480 if (responseWrapper.isEmpty()) {
481 response = buildCreatedResourceResponse(resource, context, responseWrapper);
484 response = buildErrorResponse(responseWrapper.getInnerElement());
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));
495 prepareAdditionalAudit(resource, additionalParams);
497 getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
498 ComponentTypeEnum.RESOURCE.getValue(), AuditingActionEnum.CREATE_RESOURCE_BY_API.getName(), request,
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
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) {
524 Response response = null;
525 EnumMap<AuditingFieldsKeysEnum, Object> additionalParams = new EnumMap<>(AuditingFieldsKeysEnum.class);
529 String requestURI = request.getRequestURI();
530 String url = request.getMethod() + " " + requestURI;
531 log.debug("Start handle request of {}", url);
533 //get the business logic
534 ServletContext context = request.getSession().getServletContext();
535 LifecycleBusinessLogic businessLogic = getLifecycleBL(context);
537 Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);
538 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
539 Component component = null;
540 Component responseObject = null;
541 User modifier = null;
544 if (responseWrapper.isEmpty()) {
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);
552 modifier = eitherGetUser.left().value();
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);
561 component = latestVersion.left().value();
562 String componentId = component.getUniqueId();
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);
571 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
574 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
576 if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
577 ObjectMapper mapper = new ObjectMapper();
578 changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
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);
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);
599 log.debug("change state successful !!!");
600 responseObject = actionResponse.left().value();
601 response = buildCreatedResourceResponse(responseObject, context, responseWrapper);
603 response = buildErrorResponse(responseWrapper.getInnerElement());
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);
615 auditChnageLifecycleAction(additionalParams, responseWrapper, componentType, component, responseObject, modifier, userId);
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);
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());
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);
637 private Response buildCreatedResourceResponse(Component resource, ServletContext context,
638 Wrapper<ResponseFormat> responseWrapper) throws IOException, JsonGenerationException, JsonMappingException {
639 ResponseFormat responseFormat;
641 AssetMetadataConverter assetMetadataUtils = getAssetUtils(context);
642 Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
643 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(),
645 if (resMetadata.isRight()) {
646 log.debug("Asset conversion Failed");
647 responseFormat = resMetadata.right().value();
648 responseWrapper.setInnerElement(responseFormat);
649 response = buildErrorResponse(responseFormat);
651 final AssetMetadata assetData = resMetadata.left().value();
652 assetData.setToscaModelURL(null);
654 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
655 Object representation = RepresentationUtils.toRepresentation(assetData);
656 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
661 private void handleCategories(ServletContext context, String data, Resource resource,
662 Wrapper<ResponseFormat> responseWrapper) {
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()));
672 else if (Strings.isEmpty(subcategory)) {
673 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
674 ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
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()));
686 addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
689 } catch (Exception e) {
690 log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
691 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
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))
706 if (!optionalCategory.isPresent()) {
707 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
708 ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
710 CategoryDefinition categoryDefinition = optionalCategory.get();
712 List<SubCategoryDefinition> subCaregories =
713 // Stream of all sub-categories of the relevant
715 categoryDefinition.getSubcategories().stream()
716 // filter in only relevant sub-category
717 .filter(e -> e.getName().equals(subcategory))
719 .collect(Collectors.toList());
721 if( subCaregories.isEmpty() ){
722 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
723 ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
726 categoryDefinition.setSubcategories(subCaregories);
727 resource.setCategories(Arrays.asList(categoryDefinition));
736 private void auditChnageLifecycleAction(EnumMap<AuditingFieldsKeysEnum, Object> additionalParams,
737 Wrapper<ResponseFormat> responseWrapper, ComponentTypeEnum componentType, Component component,
738 Component responseObject, User modifier, String userId) {
740 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, modifier.getFullName());
741 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, modifier.getUserId());
743 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, "");
744 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, userId);
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());
752 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, "");
753 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, "");
754 additionalParams.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, "");
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());
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());
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,"");
776 getComponentsUtils().auditExternalCrudApi(responseWrapper.getInnerElement(),
777 componentType.getValue(), AuditingActionEnum.CHANGE_LIFECYCLE_BY_API.getName(), request,
781 private Wrapper<ResponseFormat> runValidations(final String assetType) {
782 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
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);
789 // Validate USER_ID Header
790 if (responseWrapper.isEmpty()) {
791 validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER),responseWrapper);
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));
800 return responseWrapper;
803 private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
804 LifeCycleTransitionEnum transitionEnum = LifeCycleTransitionEnum.CHECKOUT;
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);
812 return Either.left(transitionEnum);