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