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.utils.CommonBeUtils;
91 import org.openecomp.sdc.common.api.Constants;
92 import org.openecomp.sdc.common.datastructure.Wrapper;
93 import org.openecomp.sdc.common.log.wrappers.Logger;
94 import org.openecomp.sdc.common.util.ValidationUtils;
95 import org.openecomp.sdc.exception.ResponseFormat;
96 import org.springframework.stereotype.Controller;
98 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
100 @Tag(name = "SDCE-7 APIs")
101 @Server(url = "/sdc")
103 public class CrudExternalServlet extends AbstractValidationsServlet {
105 private static final Logger log = Logger.getLogger(CrudExternalServlet.class);
106 private final ElementBusinessLogic elementBusinessLogic;
107 private final AssetMetadataConverter assetMetadataUtils;
108 private final LifecycleBusinessLogic lifecycleBusinessLogic;
109 private final ResourceBusinessLogic resourceBusinessLogic;
110 private final ServiceBusinessLogic serviceBusinessLogic;
112 private HttpServletRequest request;
115 public CrudExternalServlet(ComponentInstanceBusinessLogic componentInstanceBL,
116 ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager,
117 ElementBusinessLogic elementBusinessLogic, AssetMetadataConverter assetMetadataUtils,
118 LifecycleBusinessLogic lifecycleBusinessLogic, ResourceBusinessLogic resourceBusinessLogic,
119 ServiceBusinessLogic serviceBusinessLogic) {
120 super(componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
121 this.elementBusinessLogic = elementBusinessLogic;
122 this.assetMetadataUtils = assetMetadataUtils;
123 this.lifecycleBusinessLogic = lifecycleBusinessLogic;
124 this.resourceBusinessLogic = resourceBusinessLogic;
125 this.serviceBusinessLogic = serviceBusinessLogic;
129 * Creates a new Asset (Resource or Service)
134 * @param instanceIdHeader
138 @Path("/{assetType}")
139 @Consumes(MediaType.APPLICATION_JSON)
140 @Produces(MediaType.APPLICATION_JSON)
141 @Operation(parameters = {
142 @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 = {
143 @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and Asset created", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
144 @ApiResponse(responseCode = "400", description = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
145 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
146 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
147 @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
148 @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
149 @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"),
150 @ApiResponse(responseCode = "400", description = "The name provided for the newly created resource is already in use for another resource in SDC - SVC4050"),
151 @ApiResponse(responseCode = "400", description = "Invalid field format. One of the provided fields does not comply with the field rules - SVC4126"),
152 @ApiResponse(responseCode = "400", description = "Missing request body. The post request did not contain the expected body - SVC4500"),
153 @ApiResponse(responseCode = "400", description = "The resource name is missing in the request body - SVC4062"),
154 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT description has wrong format - SVC4064"),
155 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT description has wrong format (exceeds limit) - SVC4065"),
156 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT tags exceeds character limit - SVC4066"),
157 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor name exceeds character limit - SVC4067"),
158 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor release exceeds character limit - SVC4068"),
159 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT ATT Contact has wrong format - SVC4069"),
160 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT name has wrong format - SVC4070"),
161 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor name has wrong format - SVC4071"),
162 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT vendor release has wrong format - SVC4072"),
163 @ApiResponse(responseCode = "400", description = "Create VFCMT request: VFCMT name exceeds character limit - SVC4073"),
164 @ApiResponse(responseCode = "400", description = "Invalid Content. Missing PROJECT_CODE number - SVC4129"),
165 @ApiResponse(responseCode = "409", description = "Error: %1 (Service) with name '%2' already exists. - SVC4050")})
166 @PermissionAllowed(AafPermission.PermNames.WRITE_VALUE)
167 public Response createComponentExternal(
168 @Parameter(description = "Determines the format of the body of the request", required = true) @HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
169 @Parameter(description = "The user id", required = true) @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
170 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
171 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
172 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
173 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
174 @Parameter(description = "The requested asset type", required = true, schema = @Schema(allowableValues = {
175 "resources, services"})) @PathParam("assetType") final String assetType, @Parameter(hidden = true) String data) {
177 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
178 String requestURI = request.getRequestURI();
179 String url = request.getMethod() + " " + requestURI;
180 log.debug("Start handle request of {}", url);
181 Resource resource = null;
182 User modifier = null;
183 ResourceCommonInfo resourceCommonInfo = new ResourceCommonInfo(ComponentTypeEnum.RESOURCE.getValue());
184 Service service = null;
186 // Validate X-ECOMP-InstanceID Header
187 if (responseWrapper.isEmpty()) {
188 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
190 // Validate USER_ID Header
191 if (responseWrapper.isEmpty()) {
192 validateHttpCspUserIdHeader(userId, responseWrapper);
194 // Validate assetType
195 if (responseWrapper.isEmpty() && !(AssetTypeEnum.RESOURCES.getValue().equals(assetType) || AssetTypeEnum.SERVICES.getValue()
196 .equals(assetType))) {
197 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
199 if (responseWrapper.isEmpty() && AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
200 modifier = new User();
201 modifier.setUserId(userId);
202 Either<Service, ResponseFormat> convertResponse = getComponentsUtils()
203 .convertJsonToObjectUsingObjectMapper(data, modifier, Service.class, null, ComponentTypeEnum.SERVICE);
204 if (convertResponse.isRight()) {
205 responseWrapper.setInnerElement(convertResponse.right().value());
207 service = convertResponse.left().value();
209 if (service == null) {
210 responseWrapper.setInnerElement(
211 getComponentsUtils().getResponseFormat(ActionStatus.SERVICE_NOT_FOUND, ComponentTypeEnum.SERVICE.getValue()));
213 //validate name exist
214 if (responseWrapper.isEmpty() && service != null && isNullOrEmpty(service.getName())) {
215 responseWrapper.setInnerElement(
216 getComponentsUtils().getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.SERVICE.getValue()));
219 if (responseWrapper.isEmpty() && service != null && service.getCategories() != null && !service.getCategories().isEmpty()
220 && !ExternalCategoryTypeEnum.containsIgnoreCase(service.getCategories().get(0).getName())) {
221 log.debug("Service category is not supported {}", service.getCategories().get(0).getName());
222 responseWrapper.setInnerElement(
223 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.SERVICE.getValue()));
225 if (responseWrapper.isEmpty() && service != null) {
226 service.setSystemName(ValidationUtils.convertToSystemName(service.getName()));
227 log.debug("Service system name :" + service.getSystemName());
229 if (responseWrapper.isEmpty()) {
230 Either<Service, ResponseFormat> actionResponse = serviceBusinessLogic.createService(service, modifier);
231 if (actionResponse.isRight()) {
232 log.debug("Failed to create service");
233 responseWrapper.setInnerElement(actionResponse.right().value());
234 return buildErrorResponse(responseWrapper.getInnerElement());
236 // Create the service in the dataModel
237 service = actionResponse.left().value();
238 Object result = RepresentationUtils.toRepresentation(actionResponse.left().value());
239 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
240 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), result);
242 return buildErrorResponse(responseWrapper.getInnerElement());
245 //Validate resource type
246 if (responseWrapper.isEmpty()) {
247 JSONParser parser = new JSONParser();
248 JSONObject jsonObj = (JSONObject) parser.parse(data);
249 String resourceType = (String) jsonObj.get(FilterKeyEnum.RESOURCE_TYPE.getName());
250 if (StringUtils.isEmpty(resourceType) || !ResourceTypeEnum.containsName(resourceType)) {
251 resourceCommonInfo.setResourceName((String) jsonObj.get("name"));
252 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
255 // Convert the user json to a resource
256 if (responseWrapper.isEmpty()) {
257 modifier = new User();
258 modifier.setUserId(userId);
259 Either<Resource, ResponseFormat> eitherResource = getComponentsUtils()
260 .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class, null, ComponentTypeEnum.RESOURCE);
261 if (eitherResource.isRight()) {
262 responseWrapper.setInnerElement(eitherResource.right().value());
264 resource = eitherResource.left().value();
267 //validate name exist
268 if (responseWrapper.isEmpty() && isNullOrEmpty(resource.getName())) {
269 responseWrapper.setInnerElement(
270 getComponentsUtils().getResponseFormat(ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()));
272 if (responseWrapper.isEmpty()) {
273 resource.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
274 resource.setSystemName(ValidationUtils.convertToSystemName(resource.getName()));
275 resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VFCMT.name(), resource.getSystemName()));
276 handleCategories(data, resource, responseWrapper);
278 // Create the resource in the dataModel
279 if (responseWrapper.isEmpty()) {
280 resource = resourceBusinessLogic.createResource(resource, null, modifier, null, null);
281 return buildCreatedResourceResponse(resource, responseWrapper);
283 return buildErrorResponse(responseWrapper.getInnerElement());
286 } catch (IOException | ParseException e) {
287 final String message = "failed to create vfc monitoring template resource";
288 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message);
289 log.debug(message, e);
290 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
291 return buildErrorResponse(responseWrapper.getInnerElement());
292 } catch (ComponentException e) {
293 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(e);
294 responseWrapper.setInnerElement(responseFormat);
295 return buildErrorResponse(responseFormat);
297 if (AssetTypeEnum.RESOURCES.getValue().equals(assetType)) {
298 getComponentsUtils().auditCreateResourceExternalApi(responseWrapper.getInnerElement(), resourceCommonInfo, request, resource);
299 } else if (AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
300 getComponentsUtils().auditCreateServiceExternalApi(responseWrapper.getInnerElement(), request, service);
306 * Changing the lifecycle of an asset
308 * @param jsonChangeInfo The description - request body
309 * @param assetType The requested asset type.Valid values are: resources / services (for VFCMT – use "resources")
310 * @param uuid The uuid of the desired resource to be changed
311 * @param lifecycleTransition The lifecycle operation to be performed on the asset.Valid values are:Checkin / Checkout / CERTIFICATION_REQUEST
316 @Path("/{assetType}/{uuid}/lifecycleState/{lifecycleOperation}")
317 @Consumes(MediaType.APPLICATION_JSON)
318 @Produces(MediaType.APPLICATION_JSON)
319 @Operation(parameters = {
320 @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 = {
321 @ApiResponse(responseCode = "200", description = "Resource state changed", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))),
322 @ApiResponse(responseCode = "400", description = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
323 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
324 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
325 @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
326 @ApiResponse(responseCode = "405", description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
327 @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"),
328 @ApiResponse(responseCode = "403", description = "Asset is already checked-out by another user - SVC4085"),
329 @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")})
330 @PermissionAllowed(AafPermission.PermNames.WRITE_VALUE)
331 public Response changeResourceStateExternal(
332 @Parameter(description = "Determines the format of the body of the request", required = true) @HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
333 @Parameter(description = "The user id", required = true) @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
334 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
335 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
336 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
337 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
338 @Parameter(schema = @Schema(allowableValues = {
339 "checkout, checkin"}), required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition,
340 @Parameter(description = "id of component to be changed") @PathParam(value = "uuid") final String uuid,
341 @Parameter(description = "validValues: resources / services ", schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME,
342 ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam(value = "assetType") final String assetType,
343 @Parameter(hidden = true) String jsonChangeInfo) {
344 Response response = null;
346 String requestURI = request.getRequestURI();
347 String url = request.getMethod() + " " + requestURI;
348 log.debug("Start handle request of {}", url);
349 Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);
350 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
351 Component component = null;
352 Component responseObject = null;
353 User modifier = null;
355 // Validate X-ECOMP-InstanceID Header
356 if (responseWrapper.isEmpty()) {
357 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
359 if (responseWrapper.isEmpty()) {
361 Either<User, ResponseFormat> eitherGetUser = getUser(request, userId);
362 if (eitherGetUser.isRight()) {
363 ResponseFormat responseFormat = eitherGetUser.right().value();
364 responseWrapper.setInnerElement(responseFormat);
365 return buildErrorResponse(responseFormat);
367 modifier = eitherGetUser.left().value();
368 //get the component id from the uuid
369 Either<Component, ResponseFormat> latestVersion = lifecycleBusinessLogic.getLatestComponentByUuid(componentType, uuid);
370 if (latestVersion.isRight()) {
371 ResponseFormat responseFormat = latestVersion.right().value();
372 responseWrapper.setInnerElement(responseFormat);
373 return buildErrorResponse(responseFormat);
375 component = latestVersion.left().value();
376 String componentId = component.getUniqueId();
377 //validate the transition is valid
378 Either<LifeCycleTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(lifecycleTransition, modifier);
379 if (validateEnum.isRight()) {
380 ResponseFormat responseFormat = validateEnum.right().value();
381 responseWrapper.setInnerElement(responseFormat);
382 return buildErrorResponse(responseFormat);
384 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
386 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
388 if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
389 ObjectMapper mapper = new ObjectMapper();
390 changeInfo = new LifecycleChangeInfoWithAction(
391 mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
393 } catch (IOException e) {
394 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
395 log.debug("failed to convert from json {}", jsonChangeInfo, e);
396 ResponseFormat responseFormat = getComponentsUtils()
397 .getInvalidContentErrorAndAudit(modifier, componentId, AuditingActionEnum.CHECKOUT_RESOURCE);
398 responseWrapper.setInnerElement(responseFormat);
399 return buildErrorResponse(responseFormat);
401 //execute business logic
402 Either<? extends Component, ResponseFormat> actionResponse = lifecycleBusinessLogic
403 .changeComponentState(componentType, componentId, modifier, transitionEnum, changeInfo, false, true);
404 if (actionResponse.isRight()) {
405 log.info("failed to change resource state");
406 ResponseFormat responseFormat = actionResponse.right().value();
407 responseWrapper.setInnerElement(responseFormat);
408 return buildErrorResponse(responseFormat);
410 log.debug("change state successful !!!");
411 responseObject = actionResponse.left().value();
412 response = buildCreatedResourceResponse(responseObject, responseWrapper);
414 response = buildErrorResponse(responseWrapper.getInnerElement());
417 } catch (IOException e) {
418 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State");
419 log.debug("change lifecycle state failed with exception", e);
420 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
421 responseWrapper.setInnerElement(responseFormat);
422 return buildErrorResponse(responseFormat);
423 } catch (ComponentException e) {
424 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(e);
425 responseWrapper.setInnerElement(responseFormat);
426 return buildErrorResponse(responseFormat);
428 getComponentsUtils().auditChangeLifecycleAction(responseWrapper.getInnerElement(), componentType, requestId, component, responseObject,
429 new DistributionData(instanceIdHeader, requestURI), modifier);
433 private Response buildCreatedResourceResponse(Component resource, Wrapper<ResponseFormat> responseWrapper) throws IOException {
434 ResponseFormat responseFormat;
436 Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
437 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(), true, null);
438 if (resMetadata.isRight()) {
439 log.debug("Asset conversion Failed");
440 responseFormat = resMetadata.right().value();
441 responseWrapper.setInnerElement(responseFormat);
442 response = buildErrorResponse(responseFormat);
444 final AssetMetadata assetData = resMetadata.left().value();
445 assetData.setToscaModelURL(null);
446 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
447 Object representation = RepresentationUtils.toRepresentation(assetData);
448 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
453 private void handleCategories(String data, Resource resource, Wrapper<ResponseFormat> responseWrapper) {
455 JSONParser parser = new JSONParser();
456 JSONObject jsonObj = (JSONObject) parser.parse(data);
457 String category = (String) jsonObj.get(CategoryTypeEnum.CATEGORY.getValue());
458 String subcategory = (String) jsonObj.get(CategoryTypeEnum.SUBCATEGORY.getValue());
459 if (isNullOrEmpty(category)) {
460 responseWrapper.setInnerElement(
461 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
462 } else if (isNullOrEmpty(subcategory)) {
463 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
465 if (responseWrapper.isEmpty()) {
466 // get All Categories
467 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories = elementBusinessLogic.getAllResourceCategories();
468 // Error fetching categories
469 if (allResourceCategories.isRight()) {
470 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(allResourceCategories.right().value()));
472 addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
475 } catch (ParseException e) {
476 log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
477 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
481 private void addCategories(Resource resource, String category, String subcategory,
482 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories, Wrapper<ResponseFormat> responseWrapper) {
483 Optional<CategoryDefinition> optionalCategory =
484 // Stream of all the categories
485 allResourceCategories.left().value().stream()
486 // filter in only relevant category
487 .filter(e -> e.getName().equals(category))
490 if (!optionalCategory.isPresent()) {
491 responseWrapper.setInnerElement(
492 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
494 CategoryDefinition categoryDefinition = optionalCategory.get();
495 List<SubCategoryDefinition> subCaregories =
496 // Stream of all sub-categories of the relevant
499 categoryDefinition.getSubcategories().stream()
500 // filter in only relevant sub-category
501 .filter(e -> e.getName().equals(subcategory))
503 .collect(Collectors.toList());
504 if (subCaregories.isEmpty()) {
505 responseWrapper.setInnerElement(
506 getComponentsUtils().getResponseFormat(ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
508 categoryDefinition.setSubcategories(subCaregories);
509 resource.setCategories(Arrays.asList(categoryDefinition));
514 private Wrapper<ResponseFormat> runValidations(final String assetType) {
515 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
516 // Validate X-ECOMP-InstanceID Header
517 if (responseWrapper.isEmpty()) {
518 String instanceId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
519 validateXECOMPInstanceIDHeader(instanceId, responseWrapper);
521 // Validate USER_ID Header
522 if (responseWrapper.isEmpty()) {
523 validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER), responseWrapper);
525 // Validate assetType
526 if (responseWrapper.isEmpty() && !AssetTypeEnum.RESOURCES.getValue().equals(assetType) && !AssetTypeEnum.SERVICES.getValue()
527 .equals(assetType)) {
528 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
530 return responseWrapper;
533 private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
535 return Either.left(LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition));
536 } catch (IllegalArgumentException e) {
537 log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString(), e);
538 ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, "", AuditingActionEnum.CHECKOUT_RESOURCE);
539 return Either.right(error);