2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.externalapi.servlet;
23 import static com.google.common.base.Strings.isNullOrEmpty;
25 import com.fasterxml.jackson.databind.ObjectMapper;
26 import com.jcabi.aspects.Loggable;
27 import fj.data.Either;
28 import io.swagger.v3.oas.annotations.Operation;
29 import io.swagger.v3.oas.annotations.Parameter;
30 import io.swagger.v3.oas.annotations.media.ArraySchema;
31 import io.swagger.v3.oas.annotations.media.Content;
32 import io.swagger.v3.oas.annotations.media.Schema;
33 import io.swagger.v3.oas.annotations.responses.ApiResponse;
34 import io.swagger.v3.oas.annotations.servers.Server;
35 import io.swagger.v3.oas.annotations.tags.Tag;
36 import java.io.IOException;
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Optional;
40 import java.util.stream.Collectors;
41 import javax.inject.Inject;
42 import javax.servlet.http.HttpServletRequest;
43 import javax.ws.rs.Consumes;
44 import javax.ws.rs.HeaderParam;
45 import javax.ws.rs.POST;
46 import javax.ws.rs.Path;
47 import javax.ws.rs.PathParam;
48 import javax.ws.rs.Produces;
49 import javax.ws.rs.core.Context;
50 import javax.ws.rs.core.MediaType;
51 import javax.ws.rs.core.Response;
52 import org.apache.commons.lang3.StringUtils;
53 import org.json.simple.JSONObject;
54 import org.json.simple.parser.JSONParser;
55 import org.json.simple.parser.ParseException;
56 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
57 import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
58 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
59 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
60 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
61 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
62 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
63 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
64 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
65 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase;
66 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
67 import org.openecomp.sdc.be.config.BeEcompErrorManager;
68 import org.openecomp.sdc.be.dao.api.ActionStatus;
69 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
70 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
71 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
72 import org.openecomp.sdc.be.datatypes.enums.ExternalCategoryTypeEnum;
73 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
74 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
75 import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter;
76 import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata;
77 import org.openecomp.sdc.be.impl.ComponentsUtils;
78 import org.openecomp.sdc.be.impl.ServletUtils;
79 import org.openecomp.sdc.be.model.Component;
80 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
81 import org.openecomp.sdc.be.model.Resource;
82 import org.openecomp.sdc.be.model.Service;
83 import org.openecomp.sdc.be.model.User;
84 import org.openecomp.sdc.be.model.category.CategoryDefinition;
85 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
86 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
87 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
88 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo;
89 import org.openecomp.sdc.be.servlets.AbstractValidationsServlet;
90 import org.openecomp.sdc.be.servlets.RepresentationUtils;
91 import org.openecomp.sdc.be.user.UserBusinessLogic;
92 import org.openecomp.sdc.be.utils.CommonBeUtils;
93 import org.openecomp.sdc.common.api.Constants;
94 import org.openecomp.sdc.common.datastructure.Wrapper;
95 import org.openecomp.sdc.common.log.wrappers.Logger;
96 import org.openecomp.sdc.common.util.ValidationUtils;
97 import org.openecomp.sdc.exception.ResponseFormat;
98 import org.springframework.stereotype.Controller;
100 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
102 @Tag(name = "SDC External APIs")
103 @Server(url = "/sdc")
105 public class CrudExternalServlet extends AbstractValidationsServlet {
108 private HttpServletRequest request;
110 private static final Logger log = Logger.getLogger(CrudExternalServlet.class);
111 private final ElementBusinessLogic elementBusinessLogic;
112 private final AssetMetadataConverter assetMetadataUtils;
113 private final LifecycleBusinessLogic lifecycleBusinessLogic;
114 private final ResourceBusinessLogic resourceBusinessLogic;
115 private final ServiceBusinessLogic serviceBusinessLogic;
118 public CrudExternalServlet(UserBusinessLogic userBusinessLogic,
119 ComponentInstanceBusinessLogic componentInstanceBL,
120 ComponentsUtils componentsUtils, ServletUtils servletUtils,
121 ResourceImportManager resourceImportManager,
122 ElementBusinessLogic elementBusinessLogic,
123 AssetMetadataConverter assetMetadataUtils,
124 LifecycleBusinessLogic lifecycleBusinessLogic,
125 ResourceBusinessLogic resourceBusinessLogic,
126 ServiceBusinessLogic serviceBusinessLogic) {
127 super(userBusinessLogic, componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
128 this.elementBusinessLogic = elementBusinessLogic;
129 this.assetMetadataUtils = assetMetadataUtils;
130 this.lifecycleBusinessLogic = lifecycleBusinessLogic;
131 this.resourceBusinessLogic = resourceBusinessLogic;
132 this.serviceBusinessLogic = serviceBusinessLogic;
136 * Creates a new Asset (Resource or Service)
141 * @param instanceIdHeader
145 @Path("/{assetType}")
146 @Consumes(MediaType.APPLICATION_JSON)
147 @Produces(MediaType.APPLICATION_JSON)
148 @Operation(parameters = {
149 @Parameter(required = true, schema = @Schema(implementation = org.openecomp.sdc.be.model.Resource.class),
150 description = "json describe the created resource")},
151 description = "creates an asset (resource or service)", method = "POST",
152 summary = "Creates an asset (resource or service)", responses = {
153 @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and Asset created",
154 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Resource.class)))),
155 @ApiResponse(responseCode = "400", description = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
156 @ApiResponse(responseCode = "401",
157 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
158 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
159 @ApiResponse(responseCode = "404",
160 description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
161 @ApiResponse(responseCode = "405",
162 description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
163 @ApiResponse(responseCode = "500",
164 description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000"),
165 @ApiResponse(responseCode = "400",
166 description = "The name provided for the newly created resource is already in use for another resource in SDC - SVC4050"),
167 @ApiResponse(responseCode = "400",
168 description = "Invalid field format. One of the provided fields does not comply with the field rules - SVC4126"),
169 @ApiResponse(responseCode = "400",
170 description = "Missing request body. The post request did not contain the expected body - SVC4500"),
171 @ApiResponse(responseCode = "400",
172 description = "The resource name is missing in the request body - SVC4062"),
173 @ApiResponse(responseCode = "400",
174 description = "Create VFCMT request: VFCMT description has wrong format - SVC4064"),
175 @ApiResponse(responseCode = "400",
176 description = "Create VFCMT request: VFCMT description has wrong format (exceeds limit) - SVC4065"),
177 @ApiResponse(responseCode = "400",
178 description = "Create VFCMT request: VFCMT tags exceeds character limit - SVC4066"),
179 @ApiResponse(responseCode = "400",
180 description = "Create VFCMT request: VFCMT vendor name exceeds character limit - SVC4067"),
181 @ApiResponse(responseCode = "400",
182 description = "Create VFCMT request: VFCMT vendor release exceeds character limit - SVC4068"),
183 @ApiResponse(responseCode = "400",
184 description = "Create VFCMT request: VFCMT ATT Contact has wrong format - SVC4069"),
185 @ApiResponse(responseCode = "400",
186 description = "Create VFCMT request: VFCMT name has wrong format - SVC4070"),
187 @ApiResponse(responseCode = "400",
188 description = "Create VFCMT request: VFCMT vendor name has wrong format - SVC4071"),
189 @ApiResponse(responseCode = "400",
190 description = "Create VFCMT request: VFCMT vendor release has wrong format - SVC4072"),
191 @ApiResponse(responseCode = "400",
192 description = "Create VFCMT request: VFCMT name exceeds character limit - SVC4073"),
193 @ApiResponse(responseCode = "400", description = "Invalid Content. Missing PROJECT_CODE number - SVC4129"),
194 @ApiResponse(responseCode = "409",
195 description = "Error: %1 (Service) with name '%2' already exists. - SVC4050")})
196 @PermissionAllowed(AafPermission.PermNames.WRITE_VALUE)
197 public Response createComponentExternal(
198 @Parameter(description = "Determines the format of the body of the request",
199 required = true) @HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
200 @Parameter(description = "The user id",
201 required = true) @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
202 @Parameter(description = "X-ECOMP-RequestID header",
203 required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
204 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(
205 value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
206 @Parameter(description = "Determines the format of the body of the response",
207 required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
208 @Parameter(description = "The username and password",
209 required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
210 @Parameter(description = "The requested asset type", required = true,
212 allowableValues = {"resources, services"})) @PathParam("assetType") final String assetType,
213 @Parameter(hidden = true) String data) {
217 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
218 String requestURI = request.getRequestURI();
219 String url = request.getMethod() + " " + requestURI;
220 log.debug("Start handle request of {}", url);
221 Resource resource = null;
222 User modifier = null;
223 ResourceCommonInfo resourceCommonInfo = new ResourceCommonInfo(ComponentTypeEnum.RESOURCE.getValue());
224 Service service = null;
227 // Validate X-ECOMP-InstanceID Header
228 if (responseWrapper.isEmpty()) {
229 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
231 // Validate USER_ID Header
232 if (responseWrapper.isEmpty()) {
233 validateHttpCspUserIdHeader(userId, responseWrapper);
235 // Validate assetType
237 if( responseWrapper.isEmpty() && !(AssetTypeEnum.RESOURCES.getValue().equals(assetType) || AssetTypeEnum.SERVICES.getValue().equals(assetType))) {
238 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
241 if (responseWrapper.isEmpty() && AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
243 modifier = new User();
244 modifier.setUserId(userId);
245 Either<Service, ResponseFormat> convertResponse = getComponentsUtils()
246 .convertJsonToObjectUsingObjectMapper(data, modifier, Service.class,
247 null, ComponentTypeEnum.SERVICE);
248 if( convertResponse.isRight() ){
249 responseWrapper.setInnerElement(convertResponse.right().value());
252 service = convertResponse.left().value();
256 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
257 ActionStatus.SERVICE_NOT_FOUND, ComponentTypeEnum.SERVICE.getValue()));
260 //validate name exist
261 if(responseWrapper.isEmpty() && service != null && isNullOrEmpty(service.getName())){
262 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
263 ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.SERVICE.getValue()));
267 if(responseWrapper.isEmpty() && service != null && service.getCategories() != null && !service.getCategories().isEmpty() && !ExternalCategoryTypeEnum.containsIgnoreCase(service.getCategories().get(0).getName())){
268 log.debug("Service category is not supported {}", service.getCategories().get(0).getName());
269 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
270 ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.SERVICE.getValue()));
273 if(responseWrapper.isEmpty() && service != null){
274 service.setSystemName(ValidationUtils.convertToSystemName(service.getName()));
275 log.debug("Service system name :"+service.getSystemName());
278 if(responseWrapper.isEmpty()){
279 Either<Service, ResponseFormat> actionResponse = serviceBusinessLogic.createService(service, modifier);
280 if (actionResponse.isRight()) {
281 log.debug("Failed to create service");
282 responseWrapper.setInnerElement(actionResponse.right().value());
283 return buildErrorResponse(responseWrapper.getInnerElement());
286 // Create the service in the dataModel
287 service = actionResponse.left().value();
288 Object result = RepresentationUtils.toRepresentation(actionResponse.left().value());
289 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
290 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), result);
293 return buildErrorResponse(responseWrapper.getInnerElement());
299 //Validate resource type
300 if(responseWrapper.isEmpty()){
301 JSONParser parser = new JSONParser();
302 JSONObject jsonObj = (JSONObject) parser.parse(data);
303 String resourceType = (String) jsonObj.get(FilterKeyEnum.RESOURCE_TYPE.getName());
304 if( StringUtils.isEmpty(resourceType) || !ResourceTypeEnum.containsName(resourceType) ){
305 resourceCommonInfo.setResourceName((String) jsonObj.get("name"));
306 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
309 // Convert the user json to a resource
310 if (responseWrapper.isEmpty()) {
311 modifier = new User();
312 modifier.setUserId(userId);
313 Either<Resource, ResponseFormat> eitherResource = getComponentsUtils()
314 .convertJsonToObjectUsingObjectMapper(data, modifier, Resource.class,
315 null, ComponentTypeEnum.RESOURCE);
316 if( eitherResource.isRight() ){
317 responseWrapper.setInnerElement(eitherResource.right().value());
320 resource = eitherResource.left().value();
324 //validate name exist
325 if(responseWrapper.isEmpty() && isNullOrEmpty(resource.getName())){
326 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
327 ActionStatus.MISSING_COMPONENT_NAME, ComponentTypeEnum.RESOURCE.getValue()));
330 if(responseWrapper.isEmpty()){
331 resource.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
332 resource.setSystemName(ValidationUtils.convertToSystemName(resource.getName()));
333 resource.setToscaResourceName(CommonBeUtils.generateToscaResourceName(ResourceTypeEnum.VFCMT.name(),
334 resource.getSystemName()));
335 handleCategories(data, resource, responseWrapper);
337 // Create the resource in the dataModel
338 if (responseWrapper.isEmpty()) {
339 resource = resourceBusinessLogic.createResource(resource, null,
340 modifier, null, null);
341 return buildCreatedResourceResponse(resource, responseWrapper);
343 return buildErrorResponse(responseWrapper.getInnerElement());
347 } catch (IOException|ParseException e) {
348 final String message = "failed to create vfc monitoring template resource";
349 BeEcompErrorManager.getInstance().logBeRestApiGeneralError(message);
350 log.debug(message, e);
351 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
352 return buildErrorResponse(responseWrapper.getInnerElement());
353 } catch (ComponentException e){
354 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(e);
355 responseWrapper.setInnerElement(responseFormat);
356 return buildErrorResponse(responseFormat);
359 if(AssetTypeEnum.RESOURCES.getValue().equals(assetType)) {
360 getComponentsUtils().auditCreateResourceExternalApi(responseWrapper.getInnerElement(), resourceCommonInfo, request, resource);
361 } else if(AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
362 getComponentsUtils().auditCreateServiceExternalApi(responseWrapper.getInnerElement(), request, service);
368 * Changing the lifecycle of an asset
369 * @param jsonChangeInfo The description - request body
370 * @param assetType The requested asset type.Valid values are: resources / services (for VFCMT – use "resources")
371 * @param uuid The uuid of the desired resource to be changed
372 * @param lifecycleTransition The lifecycle operation to be performed on the asset.Valid values are:Checkin / Checkout / CERTIFICATION_REQUEST
377 @Path("/{assetType}/{uuid}/lifecycleState/{lifecycleOperation}")
378 @Consumes(MediaType.APPLICATION_JSON)
379 @Produces(MediaType.APPLICATION_JSON)
380 @Operation(parameters = {
381 @Parameter(required = true, schema = @Schema(implementation = org.openecomp.sdc.be.model.Resource.class),
382 description = "json describe the created resource")},
383 description = "Change Resource lifecycle State", method = "POST", responses = {
384 @ApiResponse(responseCode = "200", description = "Resource state changed",
385 content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetMetadata.class)))),
386 @ApiResponse(responseCode = "400", description = "Missing X-ECOMP-InstanceID HTTP header - POL5001"),
387 @ApiResponse(responseCode = "401",
388 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
389 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
390 @ApiResponse(responseCode = "404",
391 description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
392 @ApiResponse(responseCode = "405",
393 description = "Method Not Allowed : Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
394 @ApiResponse(responseCode = "500",
395 description = "The GET request failed either due to internal SDC problem. ECOMP Component should continue the attempts to get the needed information - POL5000"),
396 @ApiResponse(responseCode = "403", description = "Asset is already checked-out by another user - SVC4085"),
397 @ApiResponse(responseCode = "403",
398 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")})
399 @PermissionAllowed(AafPermission.PermNames.WRITE_VALUE)
400 public Response changeResourceStateExternal(
401 @Parameter(description = "Determines the format of the body of the request",
402 required = true) @HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
403 @Parameter(description = "The user id",
404 required = true) @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
405 @Parameter(description = "X-ECOMP-RequestID header",
406 required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
407 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(
408 value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
409 @Parameter(description = "Determines the format of the body of the response",
410 required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
411 @Parameter(description = "The username and password",
412 required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
413 @Parameter(schema = @Schema(allowableValues = {"checkout, checkin"}),
414 required = true) @PathParam(value = "lifecycleOperation") final String lifecycleTransition,
415 @Parameter(description = "id of component to be changed") @PathParam(value = "uuid") final String uuid,
416 @Parameter(description = "validValues: resources / services ",
417 schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME ,
418 ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam(
419 value = "assetType") final String assetType,
420 @Parameter(hidden = true) String jsonChangeInfo) {
422 Response response = null;
426 String requestURI = request.getRequestURI();
427 String url = request.getMethod() + " " + requestURI;
428 log.debug("Start handle request of {}", url);
430 Wrapper<ResponseFormat> responseWrapper = runValidations(assetType);
431 ComponentTypeEnum componentType = ComponentTypeEnum.findByParamName(assetType);
432 Component component = null;
433 Component responseObject = null;
434 User modifier = null;
437 // Validate X-ECOMP-InstanceID Header
438 if (responseWrapper.isEmpty()) {
439 validateXECOMPInstanceIDHeader(instanceIdHeader, responseWrapper);
442 if (responseWrapper.isEmpty()) {
444 Either<User, ResponseFormat> eitherGetUser = getUser(request, userId);
445 if (eitherGetUser.isRight()) {
446 ResponseFormat responseFormat = eitherGetUser.right().value();
447 responseWrapper.setInnerElement(responseFormat);
448 return buildErrorResponse(responseFormat);
450 modifier = eitherGetUser.left().value();
452 //get the component id from the uuid
453 Either<Component, ResponseFormat> latestVersion = lifecycleBusinessLogic.getLatestComponentByUuid(componentType, uuid);
454 if (latestVersion.isRight()) {
455 ResponseFormat responseFormat = latestVersion.right().value();
456 responseWrapper.setInnerElement(responseFormat);
457 return buildErrorResponse(responseFormat);
459 component = latestVersion.left().value();
460 String componentId = component.getUniqueId();
462 //validate the transition is valid
463 Either<LifeCycleTransitionEnum, ResponseFormat> validateEnum = validateTransitionEnum(lifecycleTransition, modifier);
464 if (validateEnum.isRight()) {
465 ResponseFormat responseFormat = validateEnum.right().value();
466 responseWrapper.setInnerElement(responseFormat);
467 return buildErrorResponse(responseFormat);
469 LifeCycleTransitionEnum transitionEnum = validateEnum.left().value();
472 LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction();
474 if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
475 ObjectMapper mapper = new ObjectMapper();
476 changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
479 catch (IOException e) {
480 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
481 log.debug("failed to convert from json {}", jsonChangeInfo, e);
482 ResponseFormat responseFormat = getComponentsUtils().getInvalidContentErrorAndAudit(modifier, componentId, AuditingActionEnum.CHECKOUT_RESOURCE);
483 responseWrapper.setInnerElement(responseFormat);
484 return buildErrorResponse(responseFormat);
487 //execute business logic
488 Either<? extends Component, ResponseFormat> actionResponse = lifecycleBusinessLogic.changeComponentState(componentType, componentId, modifier, transitionEnum, changeInfo, false, true);
489 if (actionResponse.isRight()) {
490 log.info("failed to change resource state");
491 ResponseFormat responseFormat = actionResponse.right().value();
492 responseWrapper.setInnerElement(responseFormat);
493 return buildErrorResponse(responseFormat);
496 log.debug("change state successful !!!");
497 responseObject = actionResponse.left().value();
498 response = buildCreatedResourceResponse(responseObject, responseWrapper);
500 response = buildErrorResponse(responseWrapper.getInnerElement());
504 } catch (IOException e) {
505 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Change Lifecycle State");
506 log.debug("change lifecycle state failed with exception", e);
507 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
508 responseWrapper.setInnerElement(responseFormat);
509 return buildErrorResponse(responseFormat);
510 } catch (ComponentException e){
511 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(e);
512 responseWrapper.setInnerElement(responseFormat);
513 return buildErrorResponse(responseFormat);
516 getComponentsUtils().auditChangeLifecycleAction(responseWrapper.getInnerElement(), componentType, requestId,
517 component, responseObject, new DistributionData(instanceIdHeader, requestURI), modifier);
521 private Response buildCreatedResourceResponse(Component resource,
522 Wrapper<ResponseFormat> responseWrapper) throws IOException {
523 ResponseFormat responseFormat;
525 Either<? extends AssetMetadata, ResponseFormat> resMetadata = assetMetadataUtils
526 .convertToSingleAssetMetadata(resource, request.getRequestURL().toString(),
528 if (resMetadata.isRight()) {
529 log.debug("Asset conversion Failed");
530 responseFormat = resMetadata.right().value();
531 responseWrapper.setInnerElement(responseFormat);
532 response = buildErrorResponse(responseFormat);
534 final AssetMetadata assetData = resMetadata.left().value();
535 assetData.setToscaModelURL(null);
537 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.CREATED));
538 Object representation = RepresentationUtils.toRepresentation(assetData);
539 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), representation);
544 private void handleCategories(String data, Resource resource,
545 Wrapper<ResponseFormat> responseWrapper) {
547 JSONParser parser = new JSONParser();
548 JSONObject jsonObj = (JSONObject) parser.parse(data);
549 String category = (String) jsonObj.get(CategoryTypeEnum.CATEGORY.getValue());
550 String subcategory = (String) jsonObj.get(CategoryTypeEnum.SUBCATEGORY.getValue());
551 if (isNullOrEmpty(category)) {
552 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
553 ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
555 else if (isNullOrEmpty(subcategory)) {
556 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
557 ActionStatus.COMPONENT_MISSING_SUBCATEGORY));
559 if (responseWrapper.isEmpty()) {
560 // get All Categories
561 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories = elementBusinessLogic
562 .getAllResourceCategories();
563 // Error fetching categories
564 if (allResourceCategories.isRight()) {
565 responseWrapper.setInnerElement(
566 getComponentsUtils().getResponseFormat(allResourceCategories.right().value()));
568 addCategories(resource, category, subcategory, allResourceCategories, responseWrapper);
571 } catch (ParseException e) {
572 log.debug("Exception occured in addCategories: {}", e.getMessage(), e);
573 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
578 private void addCategories(Resource resource, String category, String subcategory,
579 Either<List<CategoryDefinition>, ActionStatus> allResourceCategories,
580 Wrapper<ResponseFormat> responseWrapper) {
581 Optional<CategoryDefinition> optionalCategory =
582 // Stream of all the categories
583 allResourceCategories.left().value().stream()
584 // filter in only relevant category
585 .filter(e -> e.getName().equals(category))
588 if (!optionalCategory.isPresent()) {
589 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
590 ActionStatus.COMPONENT_INVALID_CATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
592 CategoryDefinition categoryDefinition = optionalCategory.get();
594 List<SubCategoryDefinition> subCaregories =
595 // Stream of all sub-categories of the relevant
597 categoryDefinition.getSubcategories().stream()
598 // filter in only relevant sub-category
599 .filter(e -> e.getName().equals(subcategory))
601 .collect(Collectors.toList());
603 if( subCaregories.isEmpty() ){
604 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(
605 ActionStatus.COMPONENT_INVALID_SUBCATEGORY, ComponentTypeEnum.RESOURCE.getValue()));
608 categoryDefinition.setSubcategories(subCaregories);
609 resource.setCategories(Arrays.asList(categoryDefinition));
615 private Wrapper<ResponseFormat> runValidations(final String assetType) {
616 Wrapper<ResponseFormat> responseWrapper = new Wrapper<>();
618 // Validate X-ECOMP-InstanceID Header
619 if (responseWrapper.isEmpty()) {
620 String instanceId = request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER);
621 validateXECOMPInstanceIDHeader(instanceId,responseWrapper);
623 // Validate USER_ID Header
624 if (responseWrapper.isEmpty()) {
625 validateHttpCspUserIdHeader(request.getHeader(Constants.USER_ID_HEADER),responseWrapper);
627 // Validate assetType
628 if (responseWrapper.isEmpty()
629 && !AssetTypeEnum.RESOURCES.getValue().equals(assetType)
630 && !AssetTypeEnum.SERVICES.getValue().equals(assetType)) {
631 responseWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
634 return responseWrapper;
637 private Either<LifeCycleTransitionEnum, ResponseFormat> validateTransitionEnum(final String lifecycleTransition, User user) {
639 return Either.left(LifeCycleTransitionEnum.getFromDisplayName(lifecycleTransition));
640 } catch (IllegalArgumentException e) {
641 log.info("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString(), e);
642 ResponseFormat error = getComponentsUtils().getInvalidContentErrorAndAudit(user, "", AuditingActionEnum.CHECKOUT_RESOURCE);
643 return Either.right(error);