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=========================================================
20 package org.openecomp.sdc.be.externalapi.servlet;
22 import static com.google.common.base.Strings.isNullOrEmpty;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.jcabi.aspects.Loggable;
26 import fj.data.Either;
27 import io.swagger.v3.oas.annotations.Operation;
28 import io.swagger.v3.oas.annotations.Parameter;
29 import io.swagger.v3.oas.annotations.media.ArraySchema;
30 import io.swagger.v3.oas.annotations.media.Content;
31 import io.swagger.v3.oas.annotations.media.Schema;
32 import io.swagger.v3.oas.annotations.responses.ApiResponse;
33 import io.swagger.v3.oas.annotations.servers.Server;
34 import io.swagger.v3.oas.annotations.tags.Tag;
35 import java.io.IOException;
36 import java.util.Arrays;
37 import java.util.List;
38 import java.util.Optional;
39 import java.util.stream.Collectors;
40 import javax.inject.Inject;
41 import javax.servlet.http.HttpServletRequest;
42 import javax.ws.rs.Consumes;
43 import javax.ws.rs.HeaderParam;
44 import javax.ws.rs.POST;
45 import javax.ws.rs.Path;
46 import javax.ws.rs.PathParam;
47 import javax.ws.rs.Produces;
48 import javax.ws.rs.core.Context;
49 import javax.ws.rs.core.MediaType;
50 import javax.ws.rs.core.Response;
51 import org.apache.commons.lang3.StringUtils;
52 import org.json.simple.JSONObject;
53 import org.json.simple.parser.JSONParser;
54 import org.json.simple.parser.ParseException;
55 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
56 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
57 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
58 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
59 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
60 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
61 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
62 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
63 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
64 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase;
65 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
66 import org.openecomp.sdc.be.config.BeEcompErrorManager;
67 import org.openecomp.sdc.be.dao.api.ActionStatus;
68 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
69 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
70 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
71 import org.openecomp.sdc.be.datatypes.enums.ExternalCategoryTypeEnum;
72 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
73 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
74 import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
75 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
76 import org.openecomp.sdc.be.impl.ComponentsUtils;
77 import org.openecomp.sdc.be.impl.ServletUtils;
78 import org.openecomp.sdc.be.model.Component;
79 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
80 import org.openecomp.sdc.be.model.Resource;
81 import org.openecomp.sdc.be.model.Service;
82 import org.openecomp.sdc.be.model.User;
83 import org.openecomp.sdc.be.model.category.CategoryDefinition;
84 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
85 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
86 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
87 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo;
88 import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
89 import org.openecomp.sdc.be.servlets.RepresentationUtils;
90 import org.openecomp.sdc.be.user.UserBusinessLogic;
91 import org.openecomp.sdc.be.utils.CommonBeUtils;
92 import org.openecomp.sdc.common.api.Constants;
93 import org.openecomp.sdc.common.datastructure.Wrapper;
94 import org.openecomp.sdc.common.log.wrappers.Logger;
95 import org.openecomp.sdc.common.util.ValidationUtils;
96 import org.openecomp.sdc.exception.ResponseFormat;
97 import org.springframework.stereotype.Controller;
99 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
101 @Tag(name = "SDC External APIs")
102 @Server(url = "/sdc")
104 public class CrudExternalServlet extends AbstractValidationsServlet {
106 private static final Logger log = Logger.getLogger(CrudExternalServlet.class);
107 private final ElementBusinessLogic elementBusinessLogic;
108 private final AssetMetadataConverter assetMetadataUtils;
109 private final LifecycleBusinessLogic lifecycleBusinessLogic;
110 private final ResourceBusinessLogic resourceBusinessLogic;
111 private final ServiceBusinessLogic serviceBusinessLogic;
113 private HttpServletRequest request;
116 public CrudExternalServlet(UserBusinessLogic userBusinessLogic, ComponentInstanceBusinessLogic componentInstanceBL,
117 ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager,
118 ElementBusinessLogic elementBusinessLogic, AssetMetadataConverter assetMetadataUtils,
119 LifecycleBusinessLogic lifecycleBusinessLogic, ResourceBusinessLogic resourceBusinessLogic,
120 ServiceBusinessLogic serviceBusinessLogic) {
121 super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
122 this.elementBusinessLogic = elementBusinessLogic;
123 this.assetMetadataUtils = assetMetadataUtils;
124 this.lifecycleBusinessLogic = lifecycleBusinessLogic;
125 this.resourceBusinessLogic = resourceBusinessLogic;
126 this.serviceBusinessLogic = serviceBusinessLogic;
130 * Creates a new Asset (Resource or Service)
135 * @param instanceIdHeader
139 @Path("/{assetType}")
140 @Consumes(MediaType.APPLICATION_JSON)
141 @Produces(MediaType.APPLICATION_JSON)
142 @Operation(parameters = {
143 @Parameter(required = true, schema = @Schema(implementation = org.openecomp.sdc.be.model.Resource.class), description = "json describe the created resource")}, description = "creates an asset (resource or service)", method = "POST", summary = "Creates an asset (resource or service)", responses = {
144 @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and Asset created", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
145 @ApiResponse(responseCode = "400", description = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
146 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
147 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
148 @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
149 @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
150 @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000"),
151 @ApiResponse(responseCode = "400", description = "The name provided for the newly created resource is already in use for another resource in SDC - SVC4050"),
152 @ApiResponse(responseCode = "400", description = "Invalid field format. One of the provided fields does not comply with the field rules - SVC4126"),
153 @ApiResponse(responseCode = "400", description = "Missing request body. The post request did not contain the expected body - SVC4500"),
154 @ApiResponse(responseCode = "400", description = "The resource name is missing in the request body - SVC4062"),
155 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT description has wrong format - SVC4064"),
156 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT description has wrong format (exceeds limit) - SVC4065"),
157 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT tags exceeds character limit - SVC4066"),
158 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor name exceeds character limit - SVC4067"),
159 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor release exceeds character limit - SVC4068"),
160 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT ATT Contact has wrong format - SVC4069"),
161 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT name has wrong format - SVC4070"),
162 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor name has wrong format - SVC4071"),
163 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor release has wrong format - SVC4072"),
164 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT name exceeds character limit - SVC4073"),
165 @ApiResponse(responseCode = "400", description = "Invalid Content. Missing PROJECT_CODE number - SVC4129"),
166 @ApiResponse(responseCode = "409", description = "Error: %1 (Service) with name '%2' already exists. - SVC4050")})
167 @PermissionAllowed(AafPermission.PermNames.WRITE_VALUE)
168 public Response createComponentExternal(
169 @Parameter(description = "Determines the format of the body of the request", required = true) @HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
170 @Parameter(description = "The user id", required = true) @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
171 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
172 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
173 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
174 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
175 @Parameter(description = "The requested asset type", required = true, schema = @Schema(allowableValues = {
176 "resources, services"})) @PathParam("assetType") final String assetType, @Parameter(hidden = true) String data) {
178 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
179 String requestURI = request.getRequestURI();
180 String url = request.getMethod() + " " + requestURI;
181 log.debug("Start handle request of {}", url);
182 Resource resource = null;
183 User modifier = null;
184 ResourceCommonInfo resourceCommonInfo = new ResourceCommonInfo(ComponentTypeEnum.RESOURCE.getValue());
185 Service service = null;
187 // Validate X-ECOMP-InstanceID Header
188 if (responseWrapper.isEmpty()) {
189 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
191 // Validate USER_ID Header
192 if (responseWrapper.isEmpty()) {
193 validateHttpCspUserIdHeader(userId, responseWrapper);
195 // Validate assetType
196 if (responseWrapper.isEmpty() && !(AssetTypeEnum.RESOURCES.getValue().equals(assetType) || AssetTypeEnum.SERVICES.getValue()
197 .equals(assetType))) {
198 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
200 if (responseWrapper.isEmpty() && AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
201 modifier = new User();
202 modifier.setUserId(userId);
203 Either<Service, ResponseFormat> convertResponse = getComponentsUtils()
204 .convertJsonToObjectUsingObjectMapper(data, modifier, Service.class, null, ComponentTypeEnum.SERVICE);
205 if (convertResponse.isRight()) {
206 responseWrapper.setInnerElement(convertResponse.right().value());
208 service = convertResponse.left().value();
210 if (service == null) {
211 responseWrapper.setInnerElement(
212 getComponentsUtils().getResponseFormat(ActionStatus.SERVICE_NOT_FOUND, ComponentTypeEnum.SERVICE.getValue()));
214 //validate name exist
215 if (responseWrapper.isEmpty() && service != null && isNullOrEmpty(service.getName())) {
216 responseWrapper.setInnerElement(
217 getComponentsUtils().getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.SERVICE.getValue()));
220 if (responseWrapper.isEmpty() && service != null && service.getCategories() != null && !service.getCategories().isEmpty()
221 && !ExternalCategoryTypeEnum.containsIgnoreCase(service.getCategories().get(0).getName())) {
222 log.debug("Service category is not supported {}", service.getCategories().get(0).getName());
223 responseWrapper.setInnerElement(
224 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.SERVICE.getValue()));
226 if (responseWrapper.isEmpty() && service != null) {
227 service.setSystemName(ValidationUtils.convertToSystemName(service.getName()));
228 log.debug("Service system name :" + service.getSystemName());
230 if (responseWrapper.isEmpty()) {
231 Either<Service, ResponseFormat> actionResponse = serviceBusinessLogic.createService(service, modifier);
232 if (actionResponse.isRight()) {
233 log.debug("Failed to create service");
234 responseWrapper.setInnerElement(actionResponse.right().value());
235 return buildErrorResponse(responseWrapper.getInnerElement());
237 // Create the service in the dataModel
238 service = actionResponse.left().value();
239 Object result = RepresentationUtils.toRepresentation(actionResponse.left().value());
240 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
241 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), result);
243 return buildErrorResponse(responseWrapper.getInnerElement());
246 //Validate resource type
247 if (responseWrapper.isEmpty()) {
248 JSONParser parser = new JSONParser();
249 JSONObject jsonObj = (JSONObject) parser.parse(data);
250 String resourceType = (String) jsonObj.get(FilterKeyEnum.RESOURCE_TYPE.getName());
251 if (StringUtils.isEmpty(resourceType) || !ResourceTypeEnum.containsName(resourceType)) {
252 resourceCommonInfo.setResourceName((String) jsonObj.get("name"));
253 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
256 // Convert the user json to a resource
257 if (responseWrapper.isEmpty()) {
258 modifier = new User();
259 modifier.setUserId(userId);
260 Either<Resource, ResponseFormat> eitherResource = getComponentsUtils()
261 .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class, null, ComponentTypeEnum.RESOURCE);
262 if (eitherResource.isRight()) {
263 responseWrapper.setInnerElement(eitherResource.right().value());
265 resource = eitherResource.left().value();
268 //validate name exist
269 if (responseWrapper.isEmpty() && isNullOrEmpty(resource.getName())) {
270 responseWrapper.setInnerElement(
271 getComponentsUtils().getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()));
273 if (responseWrapper.isEmpty()) {
274 resource.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
275 resource.setSystemName(ValidationUtils.convertToSystemName(resource.getName()));
276 resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VFCMT.name(), resource.getSystemName()));
277 handleCategories(data, resource, responseWrapper);
279 // Create the resource in the dataModel
280 if (responseWrapper.isEmpty()) {
281 resource = resourceBusinessLogic.createResource(resource, null, modifier, null, null);
282 return buildCreatedResourceResponse(resource, responseWrapper);
284 return buildErrorResponse(responseWrapper.getInnerElement());
287 } catch (IOException | ParseException e) {
288 final String message = "failed to create vfc monitoring template resource";
289 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message);
290 log.debug(message, e);
291 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
292 return buildErrorResponse(responseWrapper.getInnerElement());
293 } catch (ComponentException e) {
294 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(e);
295 responseWrapper.setInnerElement(responseFormat);
296 return buildErrorResponse(responseFormat);
298 if (AssetTypeEnum.RESOURCES.getValue().equals(assetType)) {
299 getComponentsUtils().auditCreateResourceExternalApi(responseWrapper.getInnerElement(), resourceCommonInfo, request, resource);
300 } else if (AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
301 getComponentsUtils().auditCreateServiceExternalApi(responseWrapper.getInnerElement(), request, service);
307 * Changing the lifecycle of an asset
309 * @param jsonChangeInfo The description - request body
310 * @param assetType The requested asset type.Valid values are: resources / services (for VFCMT – use "resources")
311 * @param uuid The uuid of the desired resource to be changed
312 * @param lifecycleTransition The lifecycle operation to be performed on the asset.Valid values are:Checkin / Checkout / CERTIFICATION_REQUEST
317 @Path("/{assetType}/{uuid}/lifecycleState/{lifecycleOperation}")
318 @Consumes(MediaType.APPLICATION_JSON)
319 @Produces(MediaType.APPLICATION_JSON)
320 @Operation(parameters = {
321 @Parameter(required = true, schema = @Schema(implementation = org.openecomp.sdc.be.model.Resource.class), description = "json describe the created resource")}, description = "Change Resource lifecycle State", method = "POST", responses = {
322 @ApiResponse(responseCode = "200", description = "Resource state changed", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))),
323 @ApiResponse(responseCode = "400", description = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
324 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
325 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
326 @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
327 @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
328 @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000"),
329 @ApiResponse(responseCode = "403", description = "Asset is already checked-out by another user - SVC4085"),
330 @ApiResponse(responseCode = "403", description = "Asset is being edited by different user. Only one user can checkout and edit an asset on given time. The asset will be available for checkout after the other user will checkin the asset - SVC4080")})
331 @PermissionAllowed(AafPermission.PermNames.WRITE_VALUE)
332 public Response changeResourceStateExternal(
333 @Parameter(description = "Determines the format of the body of the request", required = true) @HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
334 @Parameter(description = "The user id", required = true) @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
335 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
336 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
337 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
338 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
339 @Parameter(schema = @Schema(allowableValues = {
340 "checkout, checkin"}), required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition,
341 @Parameter(description = "id of component to be changed") @PathParam(value = "uuid") final String uuid,
342 @Parameter(description = "validValues: resources / services ", schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME,
343 ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam(value = "assetType") final String assetType,
344 @Parameter(hidden = true) String jsonChangeInfo) {
345 Response response = null;
347 String requestURI = request.getRequestURI();
348 String url = request.getMethod() + " " + requestURI;
349 log.debug("Start handle request of {}", url);
350 Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);
351 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
352 Component component = null;
353 Component responseObject = null;
354 User modifier = null;
356 // Validate X-ECOMP-InstanceID Header
357 if (responseWrapper.isEmpty()) {
358 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
360 if (responseWrapper.isEmpty()) {
362 Either<User, ResponseFormat> eitherGetUser = getUser(request, userId);
363 if (eitherGetUser.isRight()) {
364 ResponseFormat responseFormat = eitherGetUser.right().value();
365 responseWrapper.setInnerElement(responseFormat);
366 return buildErrorResponse(responseFormat);
368 modifier = eitherGetUser.left().value();
369 //get the component id from the uuid
370 Either<Component, ResponseFormat> latestVersion = lifecycleBusinessLogic.getLatestComponentByUuid(componentType, uuid);
371 if (latestVersion.isRight()) {
372 ResponseFormat responseFormat = latestVersion.right().value();
373 responseWrapper.setInnerElement(responseFormat);
374 return buildErrorResponse(responseFormat);
376 component = latestVersion.left().value();
377 String componentId = component.getUniqueId();
378 //validate the transition is valid
379 Either<LifeCycleTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(lifecycleTransition, modifier);
380 if (validateEnum.isRight()) {
381 ResponseFormat responseFormat = validateEnum.right().value();
382 responseWrapper.setInnerElement(responseFormat);
383 return buildErrorResponse(responseFormat);
385 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
387 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
389 if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
390 ObjectMapper mapper = new ObjectMapper();
391 changeInfo = new LifecycleChangeInfoWithAction(
392 mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
394 } catch (IOException e) {
395 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
396 log.debug("failed to convert from json {}", jsonChangeInfo, e);
397 ResponseFormat responseFormat = getComponentsUtils()
398 .getInvalidContentErrorAndAudit(modifier, componentId, AuditingActionEnum.CHECKOUT_RESOURCE);
399 responseWrapper.setInnerElement(responseFormat);
400 return buildErrorResponse(responseFormat);
402 //execute business logic
403 Either<? extends Component, ResponseFormat> actionResponse = lifecycleBusinessLogic
404 .changeComponentState(componentType, componentId, modifier, transitionEnum, changeInfo, false, true);
405 if (actionResponse.isRight()) {
406 log.info("failed to change resource state");
407 ResponseFormat responseFormat = actionResponse.right().value();
408 responseWrapper.setInnerElement(responseFormat);
409 return buildErrorResponse(responseFormat);
411 log.debug("change state successful !!!");
412 responseObject = actionResponse.left().value();
413 response = buildCreatedResourceResponse(responseObject, responseWrapper);
415 response = buildErrorResponse(responseWrapper.getInnerElement());
418 } catch (IOException e) {
419 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State");
420 log.debug("change lifecycle state failed with exception", e);
421 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
422 responseWrapper.setInnerElement(responseFormat);
423 return buildErrorResponse(responseFormat);
424 } catch (ComponentException e) {
425 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(e);
426 responseWrapper.setInnerElement(responseFormat);
427 return buildErrorResponse(responseFormat);
429 getComponentsUtils().auditChangeLifecycleAction(responseWrapper.getInnerElement(), componentType, requestId, component, responseObject,
430 new DistributionData(instanceIdHeader, requestURI), modifier);
434 private Response buildCreatedResourceResponse(Component resource, Wrapper<ResponseFormat> responseWrapper) throws IOException {
435 ResponseFormat responseFormat;
437 Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
438 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(), true);
439 if (resMetadata.isRight()) {
440 log.debug("Asset conversion Failed");
441 responseFormat = resMetadata.right().value();
442 responseWrapper.setInnerElement(responseFormat);
443 response = buildErrorResponse(responseFormat);
445 final AssetMetadata assetData = resMetadata.left().value();
446 assetData.setToscaModelURL(null);
447 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
448 Object representation = RepresentationUtils.toRepresentation(assetData);
449 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
454 private void handleCategories(String data, Resource resource, Wrapper<ResponseFormat> responseWrapper) {
456 JSONParser parser = new JSONParser();
457 JSONObject jsonObj = (JSONObject) parser.parse(data);
458 String category = (String) jsonObj.get(CategoryTypeEnum.CATEGORY.getValue());
459 String subcategory = (String) jsonObj.get(CategoryTypeEnum.SUBCATEGORY.getValue());
460 if (isNullOrEmpty(category)) {
461 responseWrapper.setInnerElement(
462 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
463 } else if (isNullOrEmpty(subcategory)) {
464 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
466 if (responseWrapper.isEmpty()) {
467 // get All Categories
468 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories = elementBusinessLogic.getAllResourceCategories();
469 // Error fetching categories
470 if (allResourceCategories.isRight()) {
471 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(allResourceCategories.right().value()));
473 addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
476 } catch (ParseException e) {
477 log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
478 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
482 private void addCategories(Resource resource, String category, String subcategory,
483 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories, Wrapper<ResponseFormat> responseWrapper) {
484 Optional<CategoryDefinition> optionalCategory =
485 // Stream of all the categories
486 allResourceCategories.left().value().stream()
487 // filter in only relevant category
488 .filter(e -> e.getName().equals(category))
491 if (!optionalCategory.isPresent()) {
492 responseWrapper.setInnerElement(
493 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
495 CategoryDefinition categoryDefinition = optionalCategory.get();
496 List<SubCategoryDefinition> subCaregories =
497 // Stream of all sub-categories of the relevant
500 categoryDefinition.getSubcategories().stream()
501 // filter in only relevant sub-category
502 .filter(e -> e.getName().equals(subcategory))
504 .collect(Collectors.toList());
505 if (subCaregories.isEmpty()) {
506 responseWrapper.setInnerElement(
507 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
509 categoryDefinition.setSubcategories(subCaregories);
510 resource.setCategories(Arrays.asList(categoryDefinition));
515 private Wrapper<ResponseFormat> runValidations(final String assetType) {
516 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
517 // Validate X-ECOMP-InstanceID Header
518 if (responseWrapper.isEmpty()) {
519 String instanceId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
520 validateXECOMPInstanceIDHeader(instanceId, responseWrapper);
522 // Validate USER_ID Header
523 if (responseWrapper.isEmpty()) {
524 validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER), responseWrapper);
526 // Validate assetType
527 if (responseWrapper.isEmpty() && !AssetTypeEnum.RESOURCES.getValue().equals(assetType) && !AssetTypeEnum.SERVICES.getValue()
528 .equals(assetType)) {
529 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
531 return responseWrapper;
534 private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
536 return Either.left(LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition));
537 } catch (IllegalArgumentException e) {
538 log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString(), e);
539 ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, "", AuditingActionEnum.CHECKOUT_RESOURCE);
540 return Either.right(error);