b6cb8122ce55e8b6a835ced733d0bfc67097862f
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / servlets / ComponentInstanceServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20 package org.openecomp.sdc.be.servlets;
21
22 import com.fasterxml.jackson.core.JsonProcessingException;
23 import com.fasterxml.jackson.databind.ObjectMapper;
24 import com.fasterxml.jackson.databind.SerializationFeature;
25 import com.google.gson.Gson;
26 import com.google.gson.GsonBuilder;
27 import com.google.gson.reflect.TypeToken;
28 import com.jcabi.aspects.Loggable;
29 import fj.data.Either;
30 import io.swagger.v3.oas.annotations.Operation;
31 import io.swagger.v3.oas.annotations.Parameter;
32 import io.swagger.v3.oas.annotations.media.ArraySchema;
33 import io.swagger.v3.oas.annotations.media.Content;
34 import io.swagger.v3.oas.annotations.media.Schema;
35 import io.swagger.v3.oas.annotations.responses.ApiResponse;
36 import io.swagger.v3.oas.annotations.servers.Server;
37 import io.swagger.v3.oas.annotations.tags.Tag;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.lang.reflect.Type;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Optional;
47 import java.util.Set;
48 import javax.inject.Inject;
49 import javax.servlet.http.HttpServletRequest;
50 import javax.ws.rs.Consumes;
51 import javax.ws.rs.DELETE;
52 import javax.ws.rs.GET;
53 import javax.ws.rs.HeaderParam;
54 import javax.ws.rs.POST;
55 import javax.ws.rs.PUT;
56 import javax.ws.rs.Path;
57 import javax.ws.rs.PathParam;
58 import javax.ws.rs.Produces;
59 import javax.ws.rs.QueryParam;
60 import javax.ws.rs.core.Context;
61 import javax.ws.rs.core.MediaType;
62 import javax.ws.rs.core.Response;
63 import org.apache.commons.collections.CollectionUtils;
64 import org.apache.commons.io.IOUtils;
65 import org.apache.commons.lang3.StringUtils;
66 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
67 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogicProvider;
68 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
69 import org.openecomp.sdc.be.components.impl.ComponentNodeFilterBusinessLogic;
70 import org.openecomp.sdc.be.components.impl.GroupBusinessLogic;
71 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
72 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
73 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
74 import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
75 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
76 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
77 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
78 import org.openecomp.sdc.be.config.BeEcompErrorManager;
79 import org.openecomp.sdc.be.dao.api.ActionStatus;
80 import org.openecomp.sdc.be.datamodel.ForwardingPaths;
81 import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition;
82 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
83 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
84 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
85 import org.openecomp.sdc.be.datatypes.enums.CreatedFrom;
86 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
87 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
88 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
89 import org.openecomp.sdc.be.externalapi.servlet.representation.ReplaceVNFInfo;
90 import org.openecomp.sdc.be.impl.ComponentsUtils;
91 import org.openecomp.sdc.be.impl.ServletUtils;
92 import org.openecomp.sdc.be.info.CreateAndAssotiateInfo;
93 import org.openecomp.sdc.be.info.GroupDefinitionInfo;
94 import org.openecomp.sdc.be.model.ComponentInstance;
95 import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
96 import org.openecomp.sdc.be.model.ComponentInstanceInput;
97 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
98 import org.openecomp.sdc.be.model.PropertyConstraint;
99 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
100 import org.openecomp.sdc.be.model.RequirementDefinition;
101 import org.openecomp.sdc.be.model.Service;
102 import org.openecomp.sdc.be.model.User;
103 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
104 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
105 import org.openecomp.sdc.be.resources.data.ComponentMetadataData;
106 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
107 import org.openecomp.sdc.common.api.Constants;
108 import org.openecomp.sdc.common.datastructure.Wrapper;
109 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
110 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
111 import org.openecomp.sdc.common.log.enums.StatusCode;
112 import org.openecomp.sdc.common.log.wrappers.Logger;
113 import org.openecomp.sdc.exception.ResponseFormat;
114 import org.springframework.stereotype.Controller;
115
116 /**
117  * Root resource (exposed at "/" path) .json.
118  */
119 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
120 @Path("/v1/catalog")
121 @Tag(name = "SDCE-2 APIs")
122 @Server(url = "/sdc2/rest")
123 @Controller
124 public class ComponentInstanceServlet extends AbstractValidationsServlet {
125
126     private static final String FAILED_TO_GET_PROPERTIES_OF_COMPONENT_INSTANCE_ID_IN_WITH_ID = "Failed to get properties of component instance ID: {} in {} with ID: {}";
127     private static final String GET_GROUP_ARTIFACT_BY_ID = "getGroupArtifactById";
128     private static final String GET_GROUP_ARTIFACT_BY_ID_UNEXPECTED_EXCEPTION = "getGroupArtifactById unexpected exception";
129     private static final String GET_START_HANDLE_REQUEST_OF = "(GET) Start handle request of {}";
130     private static final String START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_PROPERTY_RECEIVED_PROPERTY_IS = "Start handle request of updateResourceInstanceProperty. Received property is {}";
131     private static final String START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_ATTRIBUTE_RECEIVED_ATTRIBUTE_IS = "Start handle request of updateResourceInstanceAttribute. Received attribute is {}";
132     private static final String UPDATE_RESOURCE_INSTANCE = "Update Resource Instance";
133     private static final String RESOURCE_INSTANCE_UPDATE_RESOURCE_INSTANCE = "Resource Instance - updateResourceInstance";
134     private static final String UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION = "update resource instance with exception";
135     private static final String FAILED_TO_CONVERT_RECEIVED_DATA_TO_BE_FORMAT = "Failed to convert received data to BE format.";
136     private static final String EMPTY_BODY_WAS_SENT = "Empty body was sent.";
137     private static final String START_HANDLE_REQUEST_OF = "Start handle request of {}";
138     private static final String UNSUPPORTED_COMPONENT_TYPE = "Unsupported component type {}";
139     private static final String CREATE_AND_ASSOCIATE_RI_FAILED_WITH_EXCEPTION = "create and associate RI failed with exception: {}";
140     private static final Logger log = Logger.getLogger(ComponentInstanceServlet.class);
141     private static final Type PROPERTY_CONSTRAINT_TYPE = new TypeToken<PropertyConstraint>() {
142     }.getType();
143     private static final Gson gsonDeserializer = new GsonBuilder().registerTypeAdapter(PROPERTY_CONSTRAINT_TYPE, new PropertyConstraintDeserialiser())
144         .create();
145     private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(ComponentInstanceServlet.class.getName());
146     private static final String SERVICES = "services";
147     private final GroupBusinessLogic groupBL;
148     private final ComponentNodeFilterBusinessLogic nodeFilterBusinessLogic;
149     private final ComponentBusinessLogicProvider componentBusinessLogicProvider;
150
151     @Inject
152     public ComponentInstanceServlet(GroupBusinessLogic groupBL,
153                                     ComponentInstanceBusinessLogic componentInstanceBL, ComponentsUtils componentsUtils, ServletUtils servletUtils,
154                                     ResourceImportManager resourceImportManager, ComponentNodeFilterBusinessLogic nodeFilterBusinessLogic,
155                                     ComponentBusinessLogicProvider componentBusinessLogicProvider) {
156         super(componentInstanceBL, componentsUtils, servletUtils, resourceImportManager);
157         this.groupBL = groupBL;
158         this.nodeFilterBusinessLogic = nodeFilterBusinessLogic;
159         this.componentBusinessLogicProvider = componentBusinessLogicProvider;
160     }
161
162     @POST
163     @Path("/{containerComponentType}/{componentId}/resourceInstance")
164     @Consumes(MediaType.APPLICATION_JSON)
165     @Produces(MediaType.APPLICATION_JSON)
166     @Operation(description = "Create ComponentInstance", method = "POST", summary = "Returns created ComponentInstance", responses = {
167         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
168         @ApiResponse(responseCode = "201", description = "Component created"),
169         @ApiResponse(responseCode = "403", description = "Restricted operation"),
170         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
171         @ApiResponse(responseCode = "409", description = "Component instance already exist")})
172     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
173     public Response createComponentInstance(@Parameter(description = "RI object to be created", required = true) String data,
174                                             @PathParam("componentId") final String containerComponentId,
175                                             @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
176                                                 ComponentTypeEnum.RESOURCE_PARAM_NAME,
177                                                 ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
178                                             @HeaderParam(value = Constants.USER_ID_HEADER) @Parameter(description = "USER_ID of modifier user", required = true) String userId,
179                                             @Context final HttpServletRequest request) {
180         validateNotEmptyBody(data);
181         final ComponentInstance componentInstance;
182         try {
183             componentInstance = RepresentationUtils.fromRepresentation(data, ComponentInstance.class);
184             componentInstance.setInvariantName(null);
185             componentInstance.setCreatedFrom(CreatedFrom.UI);
186         } catch (final Exception e) {
187             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Component Instance");
188             log.debug("create component instance failed with exception", e);
189             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT, containerComponentType));
190         }
191         loggerSupportability
192             .log(LoggerSupportabilityActions.CREATE_INSTANCE, StatusCode.STARTED, "Starting to create component instance by {}", userId);
193         if (componentInstanceBusinessLogic == null) {
194             log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
195             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
196         }
197         final ComponentInstance actionResponse = componentInstanceBusinessLogic
198             .createComponentInstance(containerComponentType, containerComponentId, userId, componentInstance);
199         loggerSupportability.log(LoggerSupportabilityActions.CREATE_INSTANCE, actionResponse.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
200             "Ending to create component instance by user {}", userId);
201         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse);
202     }
203
204     @POST
205     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}")
206     @Consumes(MediaType.APPLICATION_JSON)
207     @Produces(MediaType.APPLICATION_JSON)
208     @Operation(description = "Update resource instance", method = "POST", summary = "Returns updated resource instance", responses = {
209         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
210         @ApiResponse(responseCode = "200", description = "Resource instance updated"),
211         @ApiResponse(responseCode = "403", description = "Restricted operation"),
212         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
213     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
214     public Response updateComponentInstanceMetadata(@PathParam("componentId") final String componentId,
215                                                     @PathParam("componentInstanceId") final String componentInstanceId,
216                                                     @Parameter(description = "valid values: resources / services / products", schema = @Schema(allowableValues = {
217                                                         ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
218                                                         ComponentTypeEnum.PRODUCT_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
219                                                     @Context final HttpServletRequest request) throws IOException, BusinessLogicException {
220         final String url = request.getMethod() + " " + request.getRequestURI();
221         log.debug(START_HANDLE_REQUEST_OF, url);
222         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.STARTED, "update Component Instance Metadata");
223         final String userId = request.getHeader(Constants.USER_ID_HEADER);
224         try {
225             if (componentInstanceBusinessLogic == null) {
226                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
227                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
228             }
229             componentInstanceBusinessLogic.validateUser(userId);
230             log.debug(START_HANDLE_REQUEST_OF, url);
231             final byte[] bytes = IOUtils.toByteArray(request.getInputStream());
232             if (bytes == null || bytes.length == 0) {
233                 log.info(EMPTY_BODY_WAS_SENT);
234                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
235             }
236             final String data = new String(bytes);
237             final ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
238             final Either<ComponentInstance, ResponseFormat> convertResponse = convertToResourceInstance(data);
239             if (convertResponse.isRight()) {
240                 BeEcompErrorManager.getInstance().logBeSystemError(RESOURCE_INSTANCE_UPDATE_RESOURCE_INSTANCE);
241                 log.debug(FAILED_TO_CONVERT_RECEIVED_DATA_TO_BE_FORMAT);
242                 return buildErrorResponse(convertResponse.right().value());
243             }
244             final ComponentInstance componentInstance = convertResponse.left().value();
245             final Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceBusinessLogic
246                 .updateComponentInstanceMetadata(containerComponentType, componentId, componentInstanceId, userId, componentInstance);
247             loggerSupportability
248                 .log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, actionResponse.left().value().getComponentMetadataForSupportLog(),
249                     StatusCode.COMPLETE, "update Component Instance Metadata by {}", userId);
250             if (actionResponse.isRight()) {
251                 return buildErrorResponse(actionResponse.right().value());
252             }
253             final ComponentInstance resultValue = actionResponse.left().value();
254             if (ComponentTypeEnum.SERVICE.equals(componentTypeEnum) || ComponentTypeEnum.RESOURCE.equals(componentTypeEnum)) {
255                 if (CollectionUtils.isNotEmpty(componentInstance.getDirectives())) {
256                     final Optional<CINodeFilterDataDefinition> nodeFilterDataDefinition = nodeFilterBusinessLogic
257                         .createNodeFilterIfNotExist(componentId, componentInstanceId, true, componentTypeEnum);
258                     if (!nodeFilterDataDefinition.isPresent()) {
259                         BeEcompErrorManager.getInstance().logBeSystemError("Failed to create node filter.");
260                         log.error("Failed to create node filter.");
261                         return buildErrorResponse(convertResponse.right().value());
262                     }
263                     resultValue.setNodeFilter(nodeFilterDataDefinition.get());
264                 } else {
265                     final Optional<String> result = nodeFilterBusinessLogic
266                         .deleteNodeFilterIfExists(componentId, componentInstanceId, true, componentTypeEnum);
267                     if (!result.isPresent()) {
268                         BeEcompErrorManager.getInstance().logBeSystemError("Failed to delete node filter.");
269                         log.error("Failed to delete node filter.");
270                         return buildErrorResponse(convertResponse.right().value());
271                     }
272                     resultValue.setNodeFilter(null);
273                 }
274             }
275             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value());
276         } catch (final Exception e) {
277             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_RESOURCE_INSTANCE);
278             log.debug(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e);
279             throw e;
280         }
281     }
282
283     @POST
284     @Path("/{containerComponentType}/{componentId}/resourceInstance/multipleComponentInstance")
285     @Consumes(MediaType.APPLICATION_JSON)
286     @Produces(MediaType.APPLICATION_JSON)
287     @Operation(description = "Update resource instance multiple component", method = "POST", summary = "Returns updated resource instance", responses = {
288         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
289         @ApiResponse(responseCode = "200", description = "Resource instance updated"),
290         @ApiResponse(responseCode = "403", description = "Restricted operation"),
291         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
292     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
293     public Response updateMultipleComponentInstance(@PathParam("componentId") final String componentId,
294                                                     @Parameter(description = "valid values: resources / services / products", schema = @Schema(allowableValues = {
295                                                         ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
296                                                         ComponentTypeEnum.PRODUCT_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
297                                                     @Context final HttpServletRequest request,
298                                                     @Parameter(description = "Component Instance JSON Array", required = true) final String componentInstanceJsonArray) {
299         String url = request.getMethod() + " " + request.getRequestURI();
300         log.debug(START_HANDLE_REQUEST_OF, url);
301         try {
302             log.debug(START_HANDLE_REQUEST_OF, url);
303             if (componentInstanceJsonArray == null || componentInstanceJsonArray.length() == 0) {
304                 log.info("Empty JSON list was sent.");
305                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
306             }
307             String userId = request.getHeader(Constants.USER_ID_HEADER);
308             if (componentInstanceBusinessLogic == null) {
309                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
310                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
311             }
312             Either<List<ComponentInstance>, ResponseFormat> convertResponse = convertToMultipleResourceInstance(componentInstanceJsonArray);
313             if (convertResponse.isRight()) {
314                 // Using both ECOMP error methods, show to Sofer
315                 BeEcompErrorManager.getInstance().logBeSystemError(RESOURCE_INSTANCE_UPDATE_RESOURCE_INSTANCE);
316                 log.debug(FAILED_TO_CONVERT_RECEIVED_DATA_TO_BE_FORMAT);
317                 return buildErrorResponse(convertResponse.right().value());
318             }
319             List<ComponentInstance> componentInstanceList = convertResponse.left().value();
320             List<ComponentInstance> actionResponse = componentInstanceBusinessLogic
321                 .updateComponentInstance(containerComponentType, null, componentId, userId, componentInstanceList, true);
322             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse);
323         } catch (Exception e) {
324             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_RESOURCE_INSTANCE);
325             log.debug(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e);
326             throw e;
327         }
328     }
329
330     @DELETE
331     @Path("/{containerComponentType}/{componentId}/resourceInstance/{resourceInstanceId}")
332     @Consumes(MediaType.APPLICATION_JSON)
333     @Produces(MediaType.APPLICATION_JSON)
334     @Operation(description = "Delete ResourceInstance", method = "DELETE", summary = "Returns delete resourceInstance", responses = {
335         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
336         @ApiResponse(responseCode = "201", description = "ResourceInstance deleted"),
337         @ApiResponse(responseCode = "403", description = "Restricted operation"),
338         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
339     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
340     public Response deleteResourceInstance(@PathParam("componentId") final String componentId,
341                                            @PathParam("resourceInstanceId") final String resourceInstanceId,
342                                            @Parameter(description = "valid values: resources / services / products", schema = @Schema(allowableValues = {
343                                                ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
344                                                ComponentTypeEnum.PRODUCT_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
345                                            @Context final HttpServletRequest request) {
346         String url = request.getMethod() + " " + request.getRequestURI();
347         try {
348             log.debug(START_HANDLE_REQUEST_OF, url);
349             if (componentInstanceBusinessLogic == null) {
350                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
351                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
352             }
353             String userId = request.getHeader(Constants.USER_ID_HEADER);
354             ComponentInstance actionResponse = componentInstanceBusinessLogic
355                 .deleteComponentInstance(containerComponentType, componentId, resourceInstanceId, userId);
356             loggerSupportability
357                 .log(LoggerSupportabilityActions.DELETE_COMPONENT_INSTANCE, actionResponse.getComponentMetadataForSupportLog(), StatusCode.STARTED,
358                     "DELETE_COMPONENT_INSTANCE by user {}", userId);
359             loggerSupportability
360                 .log(LoggerSupportabilityActions.DELETE_COMPONENT_INSTANCE, actionResponse.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
361                     "DELETE_COMPONENT_INSTANCE by user {}", userId);
362             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse);
363         } catch (Exception e) {
364             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Resource Instance");
365             log.debug("delete resource instance with exception", e);
366             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
367         }
368     }
369
370     @Parameter(description = "allowed values are resources /services / products", schema = @Schema(allowableValues = {
371         ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME, ComponentTypeEnum.PRODUCT_PARAM_NAME}), required = true)
372     @POST
373     @Path("/{containerComponentType}/{componentId}/resourceInstance/associate")
374     @Consumes(MediaType.APPLICATION_JSON)
375     @Produces(MediaType.APPLICATION_JSON)
376     @Operation(description = "Associate RI to RI", method = "POST", summary = "Returns created RelationshipInfo", responses = {
377         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
378         @ApiResponse(responseCode = "201", description = "Relationship created"),
379         @ApiResponse(responseCode = "403", description = "Missing information"),
380         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
381         @ApiResponse(responseCode = "409", description = "Relationship already exist")})
382     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
383     public Response associateRIToRI(
384         @Parameter(description = "unique id of the container component") @PathParam("componentId") final String componentId,
385         @Parameter(description = "allowed values are resources /services / products", schema = @Schema(allowableValues = {
386             ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
387             ComponentTypeEnum.PRODUCT_PARAM_NAME}), required = true) @PathParam("containerComponentType") final String containerComponentType,
388         @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @Parameter(description = "RelationshipInfo", required = true) String data,
389         @Context final HttpServletRequest request) {
390         String url = request.getMethod() + " " + request.getRequestURI();
391         log.debug(START_HANDLE_REQUEST_OF, url);
392         loggerSupportability
393             .log(LoggerSupportabilityActions.ASSOCIATE_RI_TO_RI, StatusCode.STARTED, "Starting to associate RI To RI for component {} ",
394                 componentId + " by " + userId);
395         try {
396             log.debug(START_HANDLE_REQUEST_OF, url);
397             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
398             if (componentInstanceBusinessLogic == null) {
399                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
400                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
401             }
402             RequirementCapabilityRelDef requirementDef = convertToRequirementCapabilityRelDef(data);
403             requirementDef.setOriginUI(true);
404             RequirementCapabilityRelDef actionResponse = componentInstanceBusinessLogic
405                 .associateRIToRI(componentId, userId, requirementDef, componentTypeEnum);
406             loggerSupportability
407                 .log(LoggerSupportabilityActions.ASSOCIATE_RI_TO_RI, StatusCode.COMPLETE, "Ended associate RI To RI for component {} ",
408                     componentId + " by " + userId);
409             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse);
410         } catch (Exception e) {
411             if (!e.getClass().equals(ComponentException.class)) {
412                 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Associate Resource Instance");
413                 log.debug("associate resource instance to another RI with exception", e);
414                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
415             }
416             throw e;
417         }
418     }
419
420     @PUT
421     @Path("/{containerComponentType}/{componentId}/resourceInstance/dissociate")
422     @Consumes(MediaType.APPLICATION_JSON)
423     @Produces(MediaType.APPLICATION_JSON)
424     @Operation(description = "Dissociate RI from RI", method = "PUT", summary = "Returns deleted RelationshipInfo", responses = {
425         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
426         @ApiResponse(responseCode = "201", description = "Relationship deleted"),
427         @ApiResponse(responseCode = "403", description = "Missing information"),
428         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
429     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
430     public Response dissociateRIFromRI(
431         @Parameter(description = "allowed values are resources /services / products", schema = @Schema(allowableValues = {
432             ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
433             ComponentTypeEnum.PRODUCT_PARAM_NAME}), required = true) @PathParam("containerComponentType") final String containerComponentType,
434         @Parameter(description = "unique id of the container component") @PathParam("componentId") final String componentId,
435         @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @Parameter(description = "RelationshipInfo", required = true) String data,
436         @Context final HttpServletRequest request) {
437         String url = request.getMethod() + " " + request.getRequestURI();
438         log.debug(START_HANDLE_REQUEST_OF, url);
439         loggerSupportability
440             .log(LoggerSupportabilityActions.UN_ASSOCIATE_RI_TO_RI, StatusCode.STARTED, "Starting to undo associate RI To RI for component {} ",
441                 componentId + " by " + userId);
442         try {
443             log.debug(START_HANDLE_REQUEST_OF, url);
444             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
445             if (componentInstanceBusinessLogic == null) {
446                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
447                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
448             }
449             RequirementCapabilityRelDef requirementDef = convertToRequirementCapabilityRelDef(data);
450             RequirementCapabilityRelDef actionResponse = componentInstanceBusinessLogic
451                 .dissociateRIFromRI(componentId, userId, requirementDef, componentTypeEnum);
452             loggerSupportability
453                 .log(LoggerSupportabilityActions.UN_ASSOCIATE_RI_TO_RI, StatusCode.COMPLETE, "Ended undo associate RI To RI for component {} ",
454                     componentId + " by " + userId);
455             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse);
456         } catch (Exception e) {
457             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Dissociate Resource Instance");
458             log.debug("dissociate resource instance from service failed with exception", e);
459             throw e;
460         }
461     }
462
463     @POST
464     @Path("/{containerComponentType}/{componentId}/resourceInstance/createAndAssociate")
465     @Consumes(MediaType.APPLICATION_JSON)
466     @Produces(MediaType.APPLICATION_JSON)
467     @Operation(description = "Create RI and associate RI to RI", method = "POST", summary = "Returns created RI and RelationshipInfo", responses = {
468         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
469         @ApiResponse(responseCode = "201", description = "RI created"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
470         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
471         @ApiResponse(responseCode = "409", description = "Relationship already exist")})
472     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
473     public Response createAndAssociateRIToRI(@PathParam("componentId") final String componentId,
474                                              @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
475                                                  ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
476                                                  ComponentTypeEnum.PRODUCT_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
477                                              @Context final HttpServletRequest request) throws IOException {
478         String url = request.getMethod() + " " + request.getRequestURI();
479         log.debug(START_HANDLE_REQUEST_OF, url);
480         try {
481             log.debug(START_HANDLE_REQUEST_OF, url);
482             InputStream inputStream = request.getInputStream();
483             byte[] bytes = IOUtils.toByteArray(inputStream);
484             if (bytes == null || bytes.length == 0) {
485                 log.info(EMPTY_BODY_WAS_SENT);
486                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
487             }
488             String userId = request.getHeader(Constants.USER_ID_HEADER);
489             String data = new String(bytes);
490             if (componentInstanceBusinessLogic == null) {
491                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
492                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
493             }
494             Either<CreateAndAssotiateInfo, ActionStatus> convertStatus = convertJsonToObject(data, CreateAndAssotiateInfo.class);
495             if (convertStatus.isRight()) {
496                 BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - createAndAssociateRIToRI");
497                 log.debug(FAILED_TO_CONVERT_RECEIVED_DATA_TO_BE_FORMAT);
498                 Either<Object, ResponseFormat> formattedResponse = Either
499                     .right(getComponentsUtils().getResponseFormat(convertStatus.right().value()));
500                 return buildErrorResponse(formattedResponse.right().value());
501             }
502             CreateAndAssotiateInfo createAndAssotiateInfo = convertStatus.left().value();
503             RequirementCapabilityRelDef requirementDef = createAndAssotiateInfo.getAssociate();
504             requirementDef.setOriginUI(true);
505             Either<CreateAndAssotiateInfo, ResponseFormat> actionResponse = componentInstanceBusinessLogic
506                 .createAndAssociateRIToRI(containerComponentType, componentId, userId, createAndAssotiateInfo);
507             if (actionResponse.isRight()) {
508                 return buildErrorResponse(actionResponse.right().value());
509             }
510             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value());
511         } catch (Exception e) {
512             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create and Associate Resource Instance");
513             log.debug("create and associate RI failed with exception", e);
514             throw e;
515         }
516     }
517
518     @POST
519     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/properties")
520     @Consumes(MediaType.APPLICATION_JSON)
521     @Produces(MediaType.APPLICATION_JSON)
522     @Operation(description = "Update resource instance property", method = "POST", summary = "Returns updated resource instance property", responses = {
523         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
524         @ApiResponse(responseCode = "201", description = "Resource instance created"),
525         @ApiResponse(responseCode = "403", description = "Restricted operation"),
526         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
527     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
528     public Response updateResourceInstanceProperties(@Parameter(description = "service id") @PathParam("componentId") final String componentId,
529                                                      @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
530                                                          ComponentTypeEnum.RESOURCE_PARAM_NAME,
531                                                          ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
532                                                      @Parameter(description = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId,
533                                                      @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
534                                                      @Context final HttpServletRequest request,
535                                                      @Parameter(description = "Component Instance Properties JSON Array", required = true) final String componentInstancePropertiesJsonArray) {
536         String url = request.getMethod() + " " + request.getRequestURI();
537         log.debug(START_HANDLE_REQUEST_OF, url);
538         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.STARTED,
539             "Starting to update Resource Instance Properties for component {} ", componentId + " by " + userId);
540         Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
541         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
542         List<ComponentInstanceProperty> propertiesToUpdate = new ArrayList<>();
543         if (errorWrapper.isEmpty()) {
544             Either<List<ComponentInstanceProperty>, ResponseFormat> propertiesToUpdateEither = convertMultipleProperties(
545                 componentInstancePropertiesJsonArray);
546             if (propertiesToUpdateEither.isRight()) {
547                 errorWrapper.setInnerElement(propertiesToUpdateEither.right().value());
548             } else {
549                 propertiesToUpdate = propertiesToUpdateEither.left().value();
550                 handleDeprecatedComponentInstancePropertyStructure(propertiesToUpdate, componentTypeEnum);
551             }
552         }
553         if (!errorWrapper.isEmpty()) {
554             return buildErrorResponse(errorWrapper.getInnerElement());
555         }
556         log.debug(START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_PROPERTY_RECEIVED_PROPERTY_IS, propertiesToUpdate);
557         if (componentInstanceBusinessLogic == null) {
558             log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
559             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
560         }
561         Either<List<ComponentInstanceProperty>, ResponseFormat> actionResponse = componentInstanceBusinessLogic
562             .createOrUpdatePropertiesValues(componentTypeEnum, componentId, componentInstanceId, propertiesToUpdate, userId);
563         if (actionResponse.isRight()) {
564             return buildErrorResponse(actionResponse.right().value());
565         }
566         List<ComponentInstanceProperty> resourceInstanceProperties = actionResponse.left().value();
567         ObjectMapper mapper = new ObjectMapper();
568         String result;
569         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.COMPLETE,
570             "Ended update Resource Instance Properties for component {} ", componentId + " by " + userId);
571         try {
572             result = mapper.writeValueAsString(resourceInstanceProperties);
573         } catch (JsonProcessingException e) {
574             log.error(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e.getMessage(), e);
575             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
576         }
577         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.COMPLETE,
578             "Ended update Resource Instance Properties for component {} ", componentId + " by user " + userId);
579         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result);
580     }
581
582     private void handleDeprecatedComponentInstancePropertyStructure(final List<ComponentInstanceProperty> propertiesToUpdate,
583                                                                     final ComponentTypeEnum componentTypeEnum) {
584         propertiesToUpdate.stream().forEach(property -> {
585             if (property.getGetInputValues() != null) {
586                 property.getGetInputValues().stream()
587                     .forEach(getInputValue -> property.setToscaFunction(createToscaFunction(getInputValue, componentTypeEnum)));
588             }
589         });
590     }
591
592     private ToscaGetFunctionDataDefinition createToscaFunction(final GetInputValueDataDefinition getInput,
593                                                                final ComponentTypeEnum componentTypeEnum) {
594         final String[] inputIdSplit = getInput.getInputId().split("\\.");
595
596         ToscaGetFunctionDataDefinition toscaFunction = new ToscaGetFunctionDataDefinition();
597         toscaFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
598         toscaFunction.setPropertyUniqueId(getInput.getInputId());
599         toscaFunction.setPropertySource(PropertySource.SELF);
600         toscaFunction.setPropertyName(inputIdSplit[1]);
601         toscaFunction.setSourceName(getSourceName(inputIdSplit[0], componentTypeEnum));
602         toscaFunction.setSourceUniqueId(inputIdSplit[0]);
603         toscaFunction.setPropertyPathFromSource(Collections.singletonList(inputIdSplit[1]));
604
605         return toscaFunction;
606     }
607
608     private String getSourceName(final String componentId, final ComponentTypeEnum componentTypeEnum) {
609         ComponentBusinessLogic compBL = componentBusinessLogicProvider.getInstance(componentTypeEnum);
610         final Either<ComponentMetadataData, StorageOperationStatus> componentEither = compBL.getComponentMetadata(componentId);
611         if (componentEither.isLeft()) {
612             return componentEither.left().value().getMetadataDataDefinition().getName();
613         }
614         return "";
615     }
616
617     @POST
618     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/inputs")
619     @Consumes(MediaType.APPLICATION_JSON)
620     @Produces(MediaType.APPLICATION_JSON)
621     @Operation(description = "Update resource instance property", method = "POST", summary = "Returns updated resource instance property", responses = {
622         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
623         @ApiResponse(responseCode = "201", description = "Resource instance created"),
624         @ApiResponse(responseCode = "403", description = "Restricted operation"),
625         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
626     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
627     public Response updateResourceInstanceInput(@Parameter(description = "service id") @PathParam("componentId") final String componentId,
628                                                 @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
629                                                     ComponentTypeEnum.RESOURCE_PARAM_NAME,
630                                                     ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
631                                                 @Parameter(description = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId,
632                                                 @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
633                                                 @Context final HttpServletRequest request,
634                                                 @Parameter(description = "Component Instance Properties JSON Array", required = true) final String componentInstanceInputsJsonArray) {
635         String url = request.getMethod() + " " + request.getRequestURI();
636         log.debug(START_HANDLE_REQUEST_OF, url);
637         Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
638         List<ComponentInstanceInput> inputsToUpdate = new ArrayList<>();
639         if (errorWrapper.isEmpty()) {
640             Either<List<ComponentInstanceInput>, ResponseFormat> inputsToUpdateEither = convertMultipleInputs(componentInstanceInputsJsonArray);
641             if (inputsToUpdateEither.isRight()) {
642                 errorWrapper.setInnerElement(inputsToUpdateEither.right().value());
643             } else {
644                 inputsToUpdate = inputsToUpdateEither.left().value();
645             }
646         }
647         if (!errorWrapper.isEmpty()) {
648             return buildErrorResponse(errorWrapper.getInnerElement());
649         }
650         log.debug(START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_PROPERTY_RECEIVED_PROPERTY_IS, inputsToUpdate);
651         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
652         if (componentInstanceBusinessLogic == null) {
653             log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
654             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
655         }
656         Either<List<ComponentInstanceInput>, ResponseFormat> actionResponse = componentInstanceBusinessLogic
657             .createOrUpdateInstanceInputValues(componentTypeEnum, componentId, componentInstanceId, inputsToUpdate, userId);
658         if (actionResponse.isRight()) {
659             return buildErrorResponse(actionResponse.right().value());
660         }
661         List<ComponentInstanceInput> resourceInstanceInput = actionResponse.left().value();
662         ObjectMapper mapper = new ObjectMapper();
663         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
664         String result;
665         loggerSupportability
666             .log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "Ending update Resource Instance Input for component {} ",
667                 componentId + " by " + userId);
668         try {
669             result = mapper.writeValueAsString(resourceInstanceInput);
670         } catch (JsonProcessingException e) {
671             log.error(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e.getMessage(), e);
672             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
673         }
674         loggerSupportability
675             .log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "Ending update Resource Instance Input for component {} ",
676                 componentId + " by user " + userId);
677         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result);
678     }
679
680     /**
681      * Updates ResourceInstance Attribute
682      *
683      * @param componentId
684      * @param containerComponentType
685      * @param componentInstanceId
686      * @param userId
687      * @param request
688      * @return
689      */
690     @POST
691     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/attributes")
692     @Consumes(MediaType.APPLICATION_JSON)
693     @Produces(MediaType.APPLICATION_JSON)
694     @Operation(description = "Update resource instance attribute", method = "POST", summary = "Returns updated resource instance property", responses = {
695         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
696         @ApiResponse(responseCode = "201", description = "Resource instance created"),
697         @ApiResponse(responseCode = "403", description = "Restricted operation"),
698         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
699     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
700     public Response updateResourceInstanceAttribute(@Parameter(description = "service id") @PathParam("componentId") final String componentId,
701                                                     @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
702                                                         ComponentTypeEnum.RESOURCE_PARAM_NAME,
703                                                         ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
704                                                     @Parameter(description = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId,
705                                                     @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) final String userId,
706                                                     @Context final HttpServletRequest request,
707                                                     @Parameter(description = "Component Instance Properties JSON Array", required = true) final String componentInstanceAttributesJsonArray) {
708         final String url = request.getMethod() + " " + request.getRequestURI();
709         log.debug(START_HANDLE_REQUEST_OF, url);
710         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.STARTED,
711             "Starting to update Resource Instance Attributes for component {} ", componentId + " by " + userId);
712         final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
713         List<ComponentInstanceAttribute> attributesToUpdate = new ArrayList<>();
714         if (errorWrapper.isEmpty()) {
715             final Either<List<ComponentInstanceAttribute>, ResponseFormat> attributesToUpdateEither = convertMultipleAttributes(
716                 componentInstanceAttributesJsonArray);
717             if (attributesToUpdateEither.isRight()) {
718                 errorWrapper.setInnerElement(attributesToUpdateEither.right().value());
719             } else {
720                 attributesToUpdate = attributesToUpdateEither.left().value();
721             }
722         }
723         if (!errorWrapper.isEmpty()) {
724             return buildErrorResponse(errorWrapper.getInnerElement());
725         }
726         log.debug(START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_ATTRIBUTE_RECEIVED_ATTRIBUTE_IS, attributesToUpdate);
727         final ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
728         if (componentInstanceBusinessLogic == null) {
729             log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
730             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
731         }
732         final Either<List<ComponentInstanceAttribute>, ResponseFormat> actionResponse = componentInstanceBusinessLogic
733             .createOrUpdateAttributeValues(componentTypeEnum, componentId, componentInstanceId, attributesToUpdate, userId);
734         if (actionResponse.isRight()) {
735             return buildErrorResponse(actionResponse.right().value());
736         }
737         final List<ComponentInstanceAttribute> resourceInstanceAttributes = actionResponse.left().value();
738         final ObjectMapper mapper = new ObjectMapper();
739         String result;
740         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.COMPLETE,
741             "Ended update Resource Instance Attributes for component {} ", componentId + " by " + userId);
742         try {
743             result = mapper.writeValueAsString(resourceInstanceAttributes);
744         } catch (JsonProcessingException e) {
745             log.error(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e.getMessage(), e);
746             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
747         }
748         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_COMPONENT_INSTANCE, StatusCode.COMPLETE,
749             "Ended update Resource Instance Attributes for component {} ", componentId + " by user " + userId);
750         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result);
751     }
752
753     @DELETE
754     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/property/{propertyId}")
755     @Consumes(MediaType.APPLICATION_JSON)
756     @Produces(MediaType.APPLICATION_JSON)
757     @Operation(description = "Update resource instance", method = "DELETE", summary = "Returns deleted resource instance property", responses = {
758         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
759         @ApiResponse(responseCode = "201", description = "Resource instance created"),
760         @ApiResponse(responseCode = "403", description = "Restricted operation"),
761         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
762     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
763     public Response deleteResourceInstanceProperty(@Parameter(description = "service id") @PathParam("componentId") final String componentId,
764                                                    @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
765                                                        ComponentTypeEnum.RESOURCE_PARAM_NAME,
766                                                        ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
767                                                    @Parameter(description = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId,
768                                                    @Parameter(description = "property id") @PathParam("propertyId") final String propertyId,
769                                                    @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
770                                                    @Context final HttpServletRequest request) {
771         loggerSupportability
772             .log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED, "Starting to delete Resource Instance Property for component {} ",
773                 componentId + " by " + userId);
774         String url = request.getMethod() + " " + request.getRequestURI();
775         log.debug(START_HANDLE_REQUEST_OF, url);
776         try {
777             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
778             loggerSupportability
779                 .log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "Ended delete Resource Instance Property for component {} ",
780                     componentId + " by " + userId);
781             if (componentInstanceBusinessLogic == null) {
782                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
783                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
784             }
785             Either<ComponentInstanceProperty, ResponseFormat> actionResponse = componentInstanceBusinessLogic
786                 .deletePropertyValue(componentTypeEnum, componentId, componentInstanceId, propertyId, userId);
787             if (actionResponse.isRight()) {
788                 return buildErrorResponse(actionResponse.right().value());
789             }
790             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null);
791         } catch (Exception e) {
792             log.error(CREATE_AND_ASSOCIATE_RI_FAILED_WITH_EXCEPTION, e.getMessage(), e);
793             throw e;
794         }
795     }
796
797     @POST
798     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/changeVersion")
799     @Consumes(MediaType.APPLICATION_JSON)
800     @Produces(MediaType.APPLICATION_JSON)
801     @Operation(description = "Update resource instance", method = "POST", summary = "Returns updated resource instance", responses = {
802         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
803         @ApiResponse(responseCode = "201", description = "Resource instance created"),
804         @ApiResponse(responseCode = "403", description = "Restricted operation"),
805         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
806     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
807     public Response changeResourceInstanceVersion(@PathParam("componentId") final String componentId,
808                                                   @PathParam("componentInstanceId") final String componentInstanceId,
809                                                   @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
810                                                       ComponentTypeEnum.RESOURCE_PARAM_NAME,
811                                                       ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
812                                                   @Context final HttpServletRequest request) throws IOException {
813         String url = request.getMethod() + " " + request.getRequestURI();
814         log.debug(START_HANDLE_REQUEST_OF, url);
815         try (InputStream inputStream = request.getInputStream()) {
816             byte[] bytes = IOUtils.toByteArray(inputStream);
817             if (bytes == null || bytes.length == 0) {
818                 log.info(EMPTY_BODY_WAS_SENT);
819                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
820             }
821             String userId = request.getHeader(Constants.USER_ID_HEADER);
822             String data = new String(bytes);
823             if (componentInstanceBusinessLogic == null) {
824                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
825                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
826             }
827             Either<ComponentInstance, ResponseFormat> convertResponse = convertToResourceInstance(data);
828             if (convertResponse.isRight()) {
829                 BeEcompErrorManager.getInstance().logBeSystemError(RESOURCE_INSTANCE_UPDATE_RESOURCE_INSTANCE);
830                 log.debug(FAILED_TO_CONVERT_RECEIVED_DATA_TO_BE_FORMAT);
831                 return buildErrorResponse(convertResponse.right().value());
832             }
833             ComponentInstance newResourceInstance = convertResponse.left().value();
834             ComponentInstance actionResponse = componentInstanceBusinessLogic
835                 .changeComponentInstanceVersion(containerComponentType, componentId, componentInstanceId, userId, newResourceInstance);
836             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse);
837         } catch (Exception e) {
838             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_RESOURCE_INSTANCE);
839             log.debug(UPDATE_RESOURCE_INSTANCE_WITH_EXCEPTION, e);
840             throw e;
841         }
842     }
843
844     @POST
845     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/groupInstance/{groupInstanceId}/property")
846     @Consumes(MediaType.APPLICATION_JSON)
847     @Produces(MediaType.APPLICATION_JSON)
848     @Operation(description = "Update resource instance property", method = "POST", summary = "Returns updated resource instance property", responses = {
849         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
850         @ApiResponse(responseCode = "201", description = "Resource instance created"),
851         @ApiResponse(responseCode = "403", description = "Restricted operation"),
852         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
853     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
854     public Response updateGroupInstanceProperty(@Parameter(description = "service id") @PathParam("componentId") final String componentId,
855                                                 @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
856                                                     ComponentTypeEnum.RESOURCE_PARAM_NAME,
857                                                     ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
858                                                 @Parameter(description = "resource instance id") @PathParam("componentInstanceId") final String componentInstanceId,
859                                                 @Parameter(description = "group instance id") @PathParam("groupInstanceId") final String groupInstanceId,
860                                                 @Parameter(description = "id of user initiating the operation") @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
861                                                 @Context final HttpServletRequest request) throws IOException {
862         String url = request.getMethod() + " " + request.getRequestURI();
863         log.debug(START_HANDLE_REQUEST_OF, url);
864         try {
865             loggerSupportability
866                 .log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.STARTED, "Starting update Group Instance Property for component {} ",
867                     componentId + " by " + userId);
868             Wrapper<String> dataWrapper = new Wrapper<>();
869             Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
870             Wrapper<ComponentInstanceProperty> propertyWrapper = new Wrapper<>();
871             validateInputStream(request, dataWrapper, errorWrapper);
872             if (errorWrapper.isEmpty()) {
873                 validateClassParse(dataWrapper.getInnerElement(), propertyWrapper, () -> ComponentInstanceProperty.class, errorWrapper);
874             }
875             if (!errorWrapper.isEmpty()) {
876                 return buildErrorResponse(errorWrapper.getInnerElement());
877             }
878             ComponentInstanceProperty property = propertyWrapper.getInnerElement();
879             log.debug(START_HANDLE_REQUEST_OF_UPDATE_RESOURCE_INSTANCE_PROPERTY_RECEIVED_PROPERTY_IS, property);
880             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
881             if (componentInstanceBusinessLogic == null) {
882                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
883                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
884             }
885             Either<ComponentInstanceProperty, ResponseFormat> actionResponse = componentInstanceBusinessLogic
886                 .createOrUpdateGroupInstancePropertyValue(componentTypeEnum, componentId, componentInstanceId, groupInstanceId, property, userId);
887             if (actionResponse.isRight()) {
888                 return buildErrorResponse(actionResponse.right().value());
889             }
890             ComponentInstanceProperty resourceInstanceProperty = actionResponse.left().value();
891             ObjectMapper mapper = new ObjectMapper();
892             String result = mapper.writeValueAsString(resourceInstanceProperty);
893             loggerSupportability
894                 .log(LoggerSupportabilityActions.UPDATE_PROPERTIES, StatusCode.COMPLETE, "Ended update Group Instance Property for component {} ",
895                     componentId + " by " + userId);
896             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result);
897         } catch (Exception e) {
898             log.error(CREATE_AND_ASSOCIATE_RI_FAILED_WITH_EXCEPTION, e.getMessage(), e);
899             throw e;
900         }
901     }
902
903     @GET
904     @Path("/{containerComponentType}/{componentId}/resourceInstance/{componentInstanceId}/groupInstance/{groupInstId}")
905     @Consumes(MediaType.APPLICATION_JSON)
906     @Produces(MediaType.APPLICATION_JSON)
907     @Operation(description = "Get group artifacts ", method = "GET", summary = "Returns artifacts metadata according to groupInstId", responses = {
908         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
909         @ApiResponse(responseCode = "200", description = "group found"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
910         @ApiResponse(responseCode = "404", description = "Group not found")})
911     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
912     public Response getGroupArtifactById(@PathParam("containerComponentType") final String containerComponentType,
913                                          @PathParam("componentId") final String componentId,
914                                          @PathParam("componentInstanceId") final String componentInstanceId,
915                                          @PathParam("groupInstId") final String groupInstId, @Context final HttpServletRequest request,
916                                          @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
917         String url = request.getMethod() + " " + request.getRequestURI();
918         log.debug(GET_START_HANDLE_REQUEST_OF, url);
919         try {
920             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
921             Either<GroupDefinitionInfo, ResponseFormat> actionResponse = groupBL
922                 .getGroupInstWithArtifactsById(componentTypeEnum, componentId, componentInstanceId, groupInstId, userId, false);
923             if (actionResponse.isRight()) {
924                 log.debug("failed to get all non abstract {}", containerComponentType);
925                 return buildErrorResponse(actionResponse.right().value());
926             }
927             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value());
928         } catch (Exception e) {
929             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(GET_GROUP_ARTIFACT_BY_ID);
930             log.debug(GET_GROUP_ARTIFACT_BY_ID_UNEXPECTED_EXCEPTION, e);
931             throw e;
932         }
933     }
934
935     // US831698
936     @GET
937     @Path("/{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/properties")
938     @Consumes(MediaType.APPLICATION_JSON)
939     @Produces(MediaType.APPLICATION_JSON)
940     @Operation(description = "Get component instance properties", method = "GET", summary = "Returns component instance properties", responses = {
941         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
942         @ApiResponse(responseCode = "200", description = "Properties found"),
943         @ApiResponse(responseCode = "403", description = "Restricted operation"),
944         @ApiResponse(responseCode = "404", description = "Component/Component Instance - not found")})
945     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
946     public Response getInstancePropertiesById(@PathParam("containerComponentType") final String containerComponentType,
947                                               @PathParam("containerComponentId") final String containerComponentId,
948                                               @PathParam("componentInstanceUniqueId") final String componentInstanceUniqueId,
949                                               @Context final HttpServletRequest request,
950                                               @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
951         String url = request.getMethod() + " " + request.getRequestURI();
952         log.debug(GET_START_HANDLE_REQUEST_OF, url);
953         List<ComponentInstanceProperty> componentInstancePropertiesById = componentInstanceBusinessLogic
954             .getComponentInstancePropertiesById(containerComponentType, containerComponentId, componentInstanceUniqueId, userId);
955         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), componentInstancePropertiesById);
956     }
957
958     @GET
959     @Path("/{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/attributes")
960     @Consumes(MediaType.APPLICATION_JSON)
961     @Produces(MediaType.APPLICATION_JSON)
962     @Operation(description = "Get component instance attributes", method = "GET", summary = "Returns component instance attributes", responses = {
963         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
964         @ApiResponse(responseCode = "200", description = "Attributes found"),
965         @ApiResponse(responseCode = "403", description = "Restricted operation"),
966         @ApiResponse(responseCode = "404", description = "Component/Component Instance - not found")})
967     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
968     public Response getInstanceAttributesById(@PathParam("containerComponentType") final String containerComponentType,
969                                               @PathParam("containerComponentId") final String containerComponentId,
970                                               @PathParam("componentInstanceUniqueId") final String componentInstanceUniqueId,
971                                               @Context final HttpServletRequest request,
972                                               @HeaderParam(value = Constants.USER_ID_HEADER) final String userId) {
973         final String url = request.getMethod() + " " + request.getRequestURI();
974         log.debug(GET_START_HANDLE_REQUEST_OF, url);
975         final List<ComponentInstanceAttribute> componentInstanceAttributesById = componentInstanceBusinessLogic
976             .getComponentInstanceAttributesById(containerComponentType, containerComponentId, componentInstanceUniqueId, userId);
977         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), componentInstanceAttributesById);
978     }
979
980     // US330353
981     @GET
982     @Path("/{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/capability/{capabilityType}/capabilityName/{capabilityName}/ownerId/{ownerId}/properties")
983     @Consumes(MediaType.APPLICATION_JSON)
984     @Produces(MediaType.APPLICATION_JSON)
985     @Operation(description = "Get component instance capability properties", method = "GET", summary = "Returns component instance capability properties", responses = {
986         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
987         @ApiResponse(responseCode = "200", description = "Properties found"),
988         @ApiResponse(responseCode = "403", description = "Restricted operation"),
989         @ApiResponse(responseCode = "404", description = "Component/Component Instance/Capability - not found")})
990     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
991     public Response getInstanceCapabilityPropertiesById(@PathParam("containerComponentType") final String containerComponentType,
992                                                         @PathParam("containerComponentId") final String containerComponentId,
993                                                         @PathParam("componentInstanceUniqueId") final String componentInstanceUniqueId,
994                                                         @PathParam("capabilityType") final String capabilityType,
995                                                         @PathParam("capabilityName") final String capabilityName,
996                                                         @PathParam("ownerId") final String ownerId, @Context final HttpServletRequest request,
997                                                         @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
998         String url = request.getMethod() + " " + request.getRequestURI();
999         log.debug(GET_START_HANDLE_REQUEST_OF, url);
1000         try {
1001             List<ComponentInstanceProperty> componentInstancePropertiesById = componentInstanceBusinessLogic
1002                 .getComponentInstanceCapabilityPropertiesById(containerComponentType, containerComponentId, componentInstanceUniqueId, capabilityType,
1003                     capabilityName, ownerId, userId);
1004             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), componentInstancePropertiesById);
1005         } catch (Exception e) {
1006             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(GET_GROUP_ARTIFACT_BY_ID);
1007             log.debug(GET_GROUP_ARTIFACT_BY_ID_UNEXPECTED_EXCEPTION, e);
1008             throw e;
1009         }
1010     }
1011
1012     //US 331281
1013     @PUT
1014     @Path("/{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/capability/{capabilityType}/capabilityName/{capabilityName}/ownerId/{ownerId}/properties")
1015     @Consumes(MediaType.APPLICATION_JSON)
1016     @Produces(MediaType.APPLICATION_JSON)
1017     @Operation(description = "Update Instance Capabilty  Property", method = "PUT", summary = "Returns updated property", responses = {
1018         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1019         @ApiResponse(responseCode = "200", description = "Resource instance capabilty property updated"),
1020         @ApiResponse(responseCode = "403", description = "Restricted operation"),
1021         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
1022         @ApiResponse(responseCode = "404", description = "Component/Component Instance/Capability - not found")})
1023     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1024     public Response updateInstanceCapabilityProperty(@PathParam("containerComponentType") final String containerComponentType,
1025                                                      @PathParam("containerComponentId") final String containerComponentId,
1026                                                      @PathParam("componentInstanceUniqueId") final String componentInstanceUniqueId,
1027                                                      @PathParam("capabilityType") final String capabilityType,
1028                                                      @PathParam("capabilityName") final String capabilityName,
1029                                                      @PathParam("ownerId") final String ownerId,
1030                                                      @Parameter(description = "Instance capabilty property to update", required = true) String data,
1031                                                      @Context final HttpServletRequest request,
1032                                                      @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
1033         String url = request.getMethod() + " " + request.getRequestURI();
1034         log.debug("(PUT) Start handle request of {}", url);
1035         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_INSTANCE_CAPABILITY_PROPERTY, StatusCode.STARTED,
1036             " Starting to update Instance Capability Property for component instance {} ", componentInstanceUniqueId + " by " + userId);
1037         try {
1038             Wrapper<ResponseFormat> errorWrapper = new Wrapper<>();
1039             List<ComponentInstanceProperty> propertiesToUpdate = new ArrayList<>();
1040             if (errorWrapper.isEmpty()) {
1041                 Either<List<ComponentInstanceProperty>, ResponseFormat> propertiesToUpdateEither = convertMultipleProperties(data);
1042                 if (propertiesToUpdateEither.isRight()) {
1043                     errorWrapper.setInnerElement(propertiesToUpdateEither.right().value());
1044                 } else {
1045                     propertiesToUpdate = propertiesToUpdateEither.left().value();
1046                 }
1047             }
1048             if (!errorWrapper.isEmpty()) {
1049                 return buildErrorResponse(errorWrapper.getInnerElement());
1050             }
1051             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
1052             Either<List<ComponentInstanceProperty>, ResponseFormat> updateCICapProperty = componentInstanceBusinessLogic
1053                 .updateInstanceCapabilityProperties(componentTypeEnum, containerComponentId, componentInstanceUniqueId, capabilityType,
1054                     capabilityName, propertiesToUpdate, userId);
1055             if (updateCICapProperty.isRight()) {
1056                 log.debug(FAILED_TO_GET_PROPERTIES_OF_COMPONENT_INSTANCE_ID_IN_WITH_ID, componentInstanceUniqueId, containerComponentType,
1057                     containerComponentId);
1058                 return buildErrorResponse(updateCICapProperty.right().value());
1059             }
1060             loggerSupportability.log(LoggerSupportabilityActions.UPDATE_INSTANCE_CAPABILITY_PROPERTY, StatusCode.COMPLETE,
1061                 " Ended to update Instance Capability Property for component instance {} ", componentInstanceUniqueId + " by " + userId);
1062             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), updateCICapProperty.left().value());
1063         } catch (Exception e) {
1064             BeEcompErrorManager.getInstance().logBeRestApiGeneralError(GET_GROUP_ARTIFACT_BY_ID);
1065             log.debug(GET_GROUP_ARTIFACT_BY_ID_UNEXPECTED_EXCEPTION, e);
1066             throw e;
1067         }
1068     }
1069
1070     @PUT
1071     @Path("/{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/requirement/{capabilityType}/requirementName/{requirementName}")
1072     @Consumes(MediaType.APPLICATION_JSON)
1073     @Produces(MediaType.APPLICATION_JSON)
1074     @Operation(description = "Update Instance Requirement", method = "PUT", summary = "Returns updated requirement", responses = {
1075         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1076         @ApiResponse(responseCode = "200", description = "Resource instance requirement updated"),
1077         @ApiResponse(responseCode = "403", description = "Restricted operation"),
1078         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
1079         @ApiResponse(responseCode = "404", description = "Component/Component Instance/Requirement - not found")})
1080     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1081     public Response updateInstanceRequirement(@PathParam("containerComponentType") final String containerComponentType,
1082                                               @PathParam("containerComponentId") final String containerComponentId,
1083                                               @PathParam("componentInstanceUniqueId") final String componentInstanceUniqueId,
1084                                               @PathParam("capabilityType") final String capabilityType,
1085                                               @PathParam("requirementName") final String requirementName,
1086                                               @Parameter(description = "Instance capabilty requirement to update", required = true) String data,
1087                                               @Context final HttpServletRequest request,
1088                                               @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
1089         String url = request.getMethod() + " " + request.getRequestURI();
1090         log.debug(START_HANDLE_REQUEST_OF, url);
1091         loggerSupportability.log(LoggerSupportabilityActions.UPDATE_INSTANCE_REQUIREMENT, StatusCode.STARTED,
1092             "Starting to update requirement {} in component instance {} by {}", requirementName, componentInstanceUniqueId, userId);
1093         try {
1094             log.debug(START_HANDLE_REQUEST_OF, url);
1095             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
1096             if (componentTypeEnum == null) {
1097                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1098                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1099             }
1100             Either<RequirementDefinition, ResponseFormat> mappedRequirementDataEither = getMappedRequirementData(data, new User(userId),
1101                 componentTypeEnum);
1102             if (mappedRequirementDataEither.isRight()) {
1103                 log.debug("Failed to update requirements");
1104                 return buildErrorResponse(mappedRequirementDataEither.right().value());
1105             }
1106             RequirementDefinition requirementDef = mappedRequirementDataEither.left().value();
1107             Either<RequirementDefinition, ResponseFormat> response = componentInstanceBusinessLogic
1108                 .updateInstanceRequirement(componentTypeEnum, containerComponentId, componentInstanceUniqueId, requirementDef, userId);
1109             if (response.isRight()) {
1110                 return buildErrorResponse(response.right().value());
1111             }
1112             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), response.left().value());
1113         } catch (ComponentException e) {
1114             throw e;
1115         } catch (Exception e) {
1116             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update component instance requirement");
1117             log.debug("Update component instance requirement with exception", e);
1118             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
1119         }
1120     }
1121
1122     private Either<RequirementDefinition, ResponseFormat> getMappedRequirementData(String inputJson, User user, ComponentTypeEnum componentTypeEnum) {
1123         return getComponentsUtils()
1124             .convertJsonToObjectUsingObjectMapper(inputJson, user, RequirementDefinition.class, AuditingActionEnum.GET_TOSCA_MODEL,
1125                 componentTypeEnum);
1126     }
1127
1128     @POST
1129     @Path("/{containerComponentType}/{containerComponentId}/serviceProxy")
1130     @Consumes(MediaType.APPLICATION_JSON)
1131     @Produces(MediaType.APPLICATION_JSON)
1132     @Operation(description = "Create service proxy", method = "POST", summary = "Returns created service proxy", responses = {
1133         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1134         @ApiResponse(responseCode = "201", description = "Service proxy created"),
1135         @ApiResponse(responseCode = "403", description = "Restricted operation"),
1136         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
1137         @ApiResponse(responseCode = "409", description = "Service proxy already exist")})
1138     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1139     public Response createServiceProxy(@Parameter(description = "RI object to be created", required = true) String data,
1140                                        @PathParam("containerComponentId") final String containerComponentId,
1141                                        @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
1142                                            ComponentTypeEnum.RESOURCE_PARAM_NAME,
1143                                            ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
1144                                        @HeaderParam(value = Constants.USER_ID_HEADER) @Parameter(description = "USER_ID of modifier user", required = true) String userId,
1145                                        @Context final HttpServletRequest request) {
1146         try {
1147             ComponentInstance componentInstance = RepresentationUtils.fromRepresentation(data, ComponentInstance.class);
1148             componentInstance.setInvariantName(null);
1149             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
1150             if (componentTypeEnum != ComponentTypeEnum.SERVICE) {
1151                 log.debug("Unsupported container component type {}", containerComponentType);
1152                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1153             }
1154             if (componentInstanceBusinessLogic == null) {
1155                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1156                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1157             }
1158             Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceBusinessLogic.createServiceProxy();
1159             if (actionResponse.isRight()) {
1160                 return buildErrorResponse(actionResponse.right().value());
1161             }
1162             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.left().value());
1163         } catch (Exception e) {
1164             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create service proxy");
1165             log.debug("Create service proxy failed with exception", e);
1166             throw e;
1167         }
1168     }
1169
1170     @DELETE
1171     @Path("/{containerComponentType}/{containerComponentId}/serviceProxy/{serviceProxyId}")
1172     @Consumes(MediaType.APPLICATION_JSON)
1173     @Produces(MediaType.APPLICATION_JSON)
1174     @Operation(description = "Delete service proxy", method = "DELETE", summary = "Returns delete service proxy", responses = {
1175         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1176         @ApiResponse(responseCode = "201", description = "Service proxy deleted"),
1177         @ApiResponse(responseCode = "403", description = "Restricted operation"),
1178         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
1179     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1180     public Response deleteServiceProxy(@PathParam("containerComponentId") final String containerComponentId,
1181                                        @PathParam("serviceProxyId") final String serviceProxyId,
1182                                        @Parameter(description = "valid values: resources / services / products", schema = @Schema(allowableValues = {
1183                                            ComponentTypeEnum.RESOURCE_PARAM_NAME,
1184                                            ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
1185                                        @Context final HttpServletRequest request) {
1186         String url = request.getMethod() + " " + request.getRequestURI();
1187         try {
1188             log.debug(START_HANDLE_REQUEST_OF, url);
1189             if (componentInstanceBusinessLogic == null) {
1190                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1191                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1192             }
1193             Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceBusinessLogic.deleteServiceProxy();
1194             if (actionResponse.isRight()) {
1195                 return buildErrorResponse(actionResponse.right().value());
1196             } else {
1197                 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT), null);
1198             }
1199         } catch (Exception e) {
1200             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete service proxy");
1201             log.debug("Delete service proxy failed with exception", e);
1202             throw e;
1203         }
1204     }
1205
1206     @POST
1207     @Path("/{containerComponentType}/{containerComponentId}/serviceProxy/{serviceProxyId}/changeVersion/{newServiceId}")
1208     @Consumes(MediaType.APPLICATION_JSON)
1209     @Produces(MediaType.APPLICATION_JSON)
1210     @Operation(description = "Update service proxy with new version", method = "POST", summary = "Returns updated service proxy", responses = {
1211         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1212         @ApiResponse(responseCode = "201", description = "Service proxy created"),
1213         @ApiResponse(responseCode = "403", description = "Restricted operation"),
1214         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")})
1215     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1216     public Response changeServiceProxyVersion(@PathParam("containerComponentId") final String containerComponentId,
1217                                               @PathParam("serviceProxyId") final String serviceProxyId,
1218                                               @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
1219                                                   ComponentTypeEnum.RESOURCE_PARAM_NAME,
1220                                                   ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
1221                                               @Context final HttpServletRequest request) {
1222         String url = request.getMethod() + " " + request.getRequestURI();
1223         log.debug(START_HANDLE_REQUEST_OF, url);
1224         try {
1225             if (componentInstanceBusinessLogic == null) {
1226                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1227                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1228             }
1229             Either<ComponentInstance, ResponseFormat> actionResponse = componentInstanceBusinessLogic.changeServiceProxyVersion();
1230             if (actionResponse.isRight()) {
1231                 return buildErrorResponse(actionResponse.right().value());
1232             }
1233             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value());
1234         } catch (Exception e) {
1235             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update service proxy with new version");
1236             log.debug("Update service proxy with new version failed with exception", e);
1237             throw e;
1238         }
1239     }
1240
1241     /**
1242      * REST API GET relation by Id Allows to get relation contained in specified component according to received Id
1243      *
1244      * @param containerComponentType
1245      * @param componentId
1246      * @param relationId
1247      * @param request
1248      * @param userId
1249      * @return Response
1250      */
1251     @GET
1252     @Path("/{containerComponentType}/{componentId}/relationId/{relationId}")
1253     @Consumes(MediaType.APPLICATION_JSON)
1254     @Produces(MediaType.APPLICATION_JSON)
1255     @Operation(description = "Get relation", method = "GET", summary = "Returns relation metadata according to relationId", responses = {
1256         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1257         @ApiResponse(responseCode = "200", description = "relation found"), @ApiResponse(responseCode = "403", description = "Restricted operation"),
1258         @ApiResponse(responseCode = "404", description = "Relation not found")})
1259     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1260     public Response getRelationById(@PathParam("containerComponentType") final String containerComponentType,
1261                                     @PathParam("componentId") final String componentId, @PathParam("relationId") final String relationId,
1262                                     @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
1263         String url = request.getMethod() + " " + request.getRequestURI();
1264         log.debug(GET_START_HANDLE_REQUEST_OF, url);
1265         try {
1266             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
1267             if (componentTypeEnum == null) {
1268                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1269                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1270             }
1271             Either<RequirementCapabilityRelDef, ResponseFormat> actionResponse = componentInstanceBusinessLogic
1272                 .getRelationById(componentId, relationId, userId, componentTypeEnum);
1273             if (actionResponse.isRight()) {
1274                 return buildErrorResponse(actionResponse.right().value());
1275             }
1276             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), actionResponse.left().value());
1277         } catch (Exception e) {
1278             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("getRelationById");
1279             log.debug("getRelationById unexpected exception", e);
1280             throw e;
1281         }
1282     }
1283
1284     private Either<ComponentInstance, ResponseFormat> convertToResourceInstance(String data) {
1285         Either<ComponentInstance, ResponseFormat> convertStatus = getComponentsUtils()
1286             .convertJsonToObjectUsingObjectMapper(data, new User(), ComponentInstance.class, null, ComponentTypeEnum.RESOURCE_INSTANCE);
1287         if (convertStatus.isRight()) {
1288             return Either.right(convertStatus.right().value());
1289         }
1290         ComponentInstance resourceInstanceInfo = convertStatus.left().value();
1291         return Either.left(resourceInstanceInfo);
1292     }
1293
1294     private Either<List<ComponentInstance>, ResponseFormat> convertToMultipleResourceInstance(String dataList) {
1295         Either<ComponentInstance[], ResponseFormat> convertStatus = getComponentsUtils()
1296             .convertJsonToObjectUsingObjectMapper(dataList, new User(), ComponentInstance[].class, null, ComponentTypeEnum.RESOURCE_INSTANCE);
1297         if (convertStatus.isRight()) {
1298             return Either.right(convertStatus.right().value());
1299         }
1300         return Either.left(Arrays.asList(convertStatus.left().value()));
1301     }
1302
1303     private Either<List<ComponentInstanceProperty>, ResponseFormat> convertMultipleProperties(String dataList) {
1304         if (StringUtils.isEmpty(dataList)) {
1305             return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_BODY));
1306         }
1307         Either<ComponentInstanceProperty[], ResponseFormat> convertStatus = getComponentsUtils()
1308             .convertJsonToObjectUsingObjectMapper(dataList, new User(), ComponentInstanceProperty[].class, null, ComponentTypeEnum.RESOURCE_INSTANCE);
1309         if (convertStatus.isRight()) {
1310             return Either.right(convertStatus.right().value());
1311         }
1312         return Either.left(Arrays.asList(convertStatus.left().value()));
1313     }
1314
1315     private Either<List<ComponentInstanceAttribute>, ResponseFormat> convertMultipleAttributes(final String dataList) {
1316         if (StringUtils.isEmpty(dataList)) {
1317             return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_BODY));
1318         }
1319         final Either<ComponentInstanceAttribute[], ResponseFormat> convertStatus = getComponentsUtils().
1320             convertJsonToObjectUsingObjectMapper(dataList, new User(), ComponentInstanceAttribute[].class, null, ComponentTypeEnum.RESOURCE_INSTANCE);
1321         if (convertStatus.isRight()) {
1322             return Either.right(convertStatus.right().value());
1323         }
1324         return Either.left(Arrays.asList(convertStatus.left().value()));
1325     }
1326
1327     private Either<List<ComponentInstanceInput>, ResponseFormat> convertMultipleInputs(String dataList) {
1328         if (StringUtils.isEmpty(dataList)) {
1329             return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_BODY));
1330         }
1331         Either<ComponentInstanceInput[], ResponseFormat> convertStatus = getComponentsUtils()
1332             .convertJsonToObjectUsingObjectMapper(dataList, new User(), ComponentInstanceInput[].class, null, ComponentTypeEnum.RESOURCE_INSTANCE);
1333         if (convertStatus.isRight()) {
1334             return Either.right(convertStatus.right().value());
1335         }
1336         return Either.left(Arrays.asList(convertStatus.left().value()));
1337     }
1338
1339     private RequirementCapabilityRelDef convertToRequirementCapabilityRelDef(String data) {
1340         Either<RequirementCapabilityRelDef, ActionStatus> convertStatus = convertJsonToObject(data, RequirementCapabilityRelDef.class);
1341         if (convertStatus.isRight()) {
1342             throw new ByActionStatusComponentException(convertStatus.right().value());
1343         }
1344         return convertStatus.left().value();
1345     }
1346
1347     @Override
1348     public <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) {
1349         try {
1350             log.trace("convert json to object. json=\n {}", data);
1351             T t;
1352             t = gsonDeserializer.fromJson(data, clazz);
1353             if (t == null) {
1354                 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
1355                 log.debug("object is null after converting from json");
1356                 return Either.right(ActionStatus.INVALID_CONTENT);
1357             }
1358             return Either.left(t);
1359         } catch (Exception e) {
1360             // INVALID JSON
1361             BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
1362             log.debug("failed to convert from json", e);
1363             return Either.right(ActionStatus.INVALID_CONTENT);
1364         }
1365     }
1366
1367     @GET
1368     @Path("/{containerComponentType}/{componentId}/paths-to-delete")
1369     @Produces(MediaType.APPLICATION_JSON)
1370     @Operation(description = "Check if forwarding path to delete on version change", method = "GET", summary = "Returns forwarding paths to delete", responses = {
1371         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class))))})
1372     public Response changeResourceInstanceVersion(@PathParam("componentId") String componentId,
1373                                                   @QueryParam("componentInstanceId") final String oldComponentInstanceId,
1374                                                   @QueryParam("newComponentInstanceId") final String newComponentInstanceId,
1375                                                   @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {
1376                                                       ComponentTypeEnum.RESOURCE_PARAM_NAME,
1377                                                       ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
1378                                                   @Context final HttpServletRequest request) {
1379         if (oldComponentInstanceId == null) {
1380             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_OLD_COMPONENT_INSTANCE));
1381         }
1382         if (newComponentInstanceId == null) {
1383             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_NEW_COMPONENT_INSTANCE));
1384         }
1385         String url = request.getMethod() + " " + request.getRequestURI();
1386         log.debug(START_HANDLE_REQUEST_OF, url);
1387         if (componentInstanceBusinessLogic == null) {
1388             log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1389             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1390         }
1391         ComponentInstance newComponentInstance;
1392         if (StringUtils.isNotEmpty(newComponentInstanceId)) {
1393             newComponentInstance = new ComponentInstance();
1394             newComponentInstance.setToscaPresentationValue(JsonPresentationFields.CI_COMPONENT_UID, newComponentInstanceId);
1395         } else {
1396             log.error("missing component id");
1397             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.MISSING_DATA));
1398         }
1399         Either<Set<String>, ResponseFormat> actionResponse = componentInstanceBusinessLogic
1400             .forwardingPathOnVersionChange(containerComponentType, componentId, oldComponentInstanceId, newComponentInstance);
1401         if (actionResponse.isRight()) {
1402             return buildErrorResponse(actionResponse.right().value());
1403         }
1404         ForwardingPaths forwardingPaths = new ForwardingPaths();
1405         forwardingPaths.setForwardingPathToDelete(actionResponse.left().value());
1406         return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), forwardingPaths);
1407     }
1408
1409     @POST
1410     @Path("/services/{componentId}/copyComponentInstance/{componentInstanceId}")
1411     @Consumes(MediaType.APPLICATION_JSON)
1412     @Produces((MediaType.APPLICATION_JSON))
1413     @Operation(description = "Copy Component Instance", method = "POST", summary = "Returns updated service information", responses = {
1414         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Service.class)))),
1415         @ApiResponse(responseCode = "201", description = "Copy and Paste Success"),
1416         @ApiResponse(responseCode = "403", description = "Restricted Operation"),
1417         @ApiResponse(responseCode = "400", description = "Invalid Content / Missing content")})
1418     public Response copyComponentInstance(
1419         @Parameter(description = "service unique id in pasted canvas") @PathParam("componentId") final String containerComponentId,
1420         @Parameter(description = "Data for copying", required = true) String data, @PathParam("componentInstanceId") final String componentInstanceId,
1421         @Context final HttpServletRequest request) {
1422         log.info("Start to copy component instance");
1423         String userId = request.getHeader(Constants.USER_ID_HEADER);
1424         final String CNTAINER_CMPT_TYPE = SERVICES;
1425         try {
1426             ComponentInstance inputComponentInstance = RepresentationUtils.fromRepresentation(data, ComponentInstance.class);
1427             inputComponentInstance.setInvariantName(null);
1428             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(CNTAINER_CMPT_TYPE);
1429             if (componentInstanceBusinessLogic == null) {
1430                 log.debug(UNSUPPORTED_COMPONENT_TYPE, componentTypeEnum);
1431                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, SERVICES));
1432             }
1433             Either<Map<String, ComponentInstance>, ResponseFormat> copyComponentInstance = componentInstanceBusinessLogic
1434                 .copyComponentInstance(inputComponentInstance, containerComponentId, componentInstanceId, userId);
1435             if (copyComponentInstance.isRight()) {
1436                 log.error("Failed to copy ComponentInstance {}", copyComponentInstance.right().value());
1437                 return buildErrorResponse(copyComponentInstance.right().value());
1438             }
1439             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), copyComponentInstance.left().value());
1440         } catch (Exception e) {
1441             log.error("Failed to convert json to Map { }", data, e);
1442             return buildErrorResponse(
1443                 getComponentsUtils().getResponseFormat(ActionStatus.USER_DEFINED, "Failed to get the copied component instance information"));
1444         }
1445     }
1446
1447     @POST
1448     @Path("/{containerComponentType}/{componentId}/batchDeleteResourceInstances/")
1449     @Consumes(MediaType.APPLICATION_JSON)
1450     @Produces(MediaType.APPLICATION_JSON)
1451     @Operation(description = "Batch Delete ResourceInstances", method = "POST", responses = {
1452         @ApiResponse(responseCode = "203", description = "ResourceInstances deleted"),
1453         @ApiResponse(responseCode = "403", description = "Restricted Operation"),
1454         @ApiResponse(responseCode = "400", description = "Invalid Content / Missing Content")})
1455     public Response batchDeleteResourceInstances(
1456         @Parameter(description = "valid values: resources / services / products", schema = @Schema(allowableValues = {
1457             ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
1458             ComponentTypeEnum.PRODUCT_PARAM_NAME})) @PathParam("containerComponentType") final String containerComponentType,
1459         @PathParam("componentId") final String componentId, @Context final HttpServletRequest request,
1460         @Parameter(description = "Component Instance Id List", required = true) final String componentInstanceIdLisStr) {
1461         try {
1462             if (componentInstanceIdLisStr == null || componentInstanceIdLisStr.isEmpty()) {
1463                 log.error("Empty JSON List was sent", componentInstanceIdLisStr);
1464                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
1465             }
1466             if (componentInstanceBusinessLogic == null) {
1467                 log.error(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1468                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1469             }
1470             Either<List<String>, ResponseFormat> convertResponse = convertToStringList(componentInstanceIdLisStr);
1471             if (convertResponse.isRight()) {
1472                 BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - batchDeleteResourceInstances");
1473                 log.error(FAILED_TO_CONVERT_RECEIVED_DATA_TO_BE_FORMAT);
1474                 return buildErrorResponse(convertResponse.right().value());
1475             }
1476             String userId = request.getHeader(Constants.USER_ID_HEADER);
1477             List<String> componentInstanceIdList = convertResponse.left().value();
1478             log.debug("batchDeleteResourceInstances componentInstanceIdList is {}", componentInstanceIdList);
1479             Map<String, List<String>> deleteErrorMap = componentInstanceBusinessLogic
1480                 .batchDeleteComponentInstance(containerComponentType, componentId, componentInstanceIdList, userId);
1481             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), deleteErrorMap);
1482         } catch (Exception e) {
1483             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Batch Delete ResourceInstances");
1484             log.error("batch delete resource instances with exception", e);
1485             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
1486         }
1487     }
1488
1489     @PUT
1490     @Path("/{containerComponentType}/{componentId}/resourceInstance/batchDissociate")
1491     @Consumes(MediaType.APPLICATION_JSON)
1492     @Produces(MediaType.APPLICATION_JSON)
1493     @Operation(description = "Batch Dissociate RI from RI", method = "PUT", summary = "Returns deleted RelationShip Info", responses = {
1494         @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
1495         @ApiResponse(responseCode = "201", description = "Relationship deleted"),
1496         @ApiResponse(responseCode = "403", description = "Missing Information"),
1497         @ApiResponse(responseCode = "400", description = "Invalid Content / Missing Content")})
1498     public Response batchDissociateRIFromRI(
1499         @Parameter(description = "allowed values are resources/services/products", schema = @Schema(allowableValues = {
1500             ComponentTypeEnum.RESOURCE_PARAM_NAME, ComponentTypeEnum.SERVICE_PARAM_NAME,
1501             ComponentTypeEnum.PRODUCT_PARAM_NAME}), required = true) @PathParam("containerComponentType") final String containerComponentType,
1502         @Parameter(description = "unique id of the container component") @PathParam("componentId") final String componentId,
1503         @HeaderParam(value = Constants.USER_ID_HEADER) String userId, @Parameter(description = "RelationshipInfo", required = true) String data,
1504         @Context final HttpServletRequest request) {
1505         try {
1506             if (data == null || data.length() == 0) {
1507                 log.info("Empty JSON list was sent");
1508                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
1509             }
1510             ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
1511             if (componentInstanceBusinessLogic == null) {
1512                 log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
1513                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1514             }
1515             Either<List<RequirementCapabilityRelDef>, ResponseFormat> regInfoWs = convertToRequirementCapabilityRelDefList(data);
1516             if (regInfoWs.isRight()) {
1517                 BeEcompErrorManager.getInstance().logBeSystemError("Resource Instance - batch dissociateRIFromRI");
1518                 log.debug("Failed to convert received data to BE format");
1519                 return buildErrorResponse(regInfoWs.right().value());
1520             }
1521             List<RequirementCapabilityRelDef> requirementDefList = regInfoWs.left().value();
1522             List<RequirementCapabilityRelDef> delOkResult = componentInstanceBusinessLogic
1523                 .batchDissociateRIFromRI(componentId, userId, requirementDefList, componentTypeEnum);
1524             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), delOkResult);
1525         } catch (Exception e) {
1526             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Batch Dissociate Resource Instance");
1527             log.debug("batch dissociate resource instance from service failed with exception", e);
1528             return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
1529         }
1530     }
1531
1532     private Either<List<String>, ResponseFormat> convertToStringList(String datalist) {
1533         Either<String[], ResponseFormat> convertStatus = getComponentsUtils()
1534             .convertJsonToObjectUsingObjectMapper(datalist, new User(), String[].class, null, null);
1535         if (convertStatus.isRight()) {
1536             return Either.right(convertStatus.right().value());
1537         }
1538         return Either.left(Arrays.asList(convertStatus.left().value()));
1539     }
1540
1541     private Either<List<RequirementCapabilityRelDef>, ResponseFormat> convertToRequirementCapabilityRelDefList(String data) {
1542         Either<RequirementCapabilityRelDef[], ResponseFormat> convertStatus = getComponentsUtils()
1543             .convertJsonToObjectUsingObjectMapper(data, new User(), RequirementCapabilityRelDef[].class, null, null);
1544         if (convertStatus.isRight()) {
1545             return Either.right(convertStatus.right().value());
1546         }
1547         return Either.left(Arrays.asList(convertStatus.left().value()));
1548     }
1549
1550     @POST
1551     @Path("/services/replaceVNF")
1552     @Operation(description = "Replace new VNF based on the existing VNF", method = "POST", summary = "Return whether the replace VNF is successful", responses = {
1553         @ApiResponse(responseCode = "200", description = "ECOMP component is authenticated and list of Catalog Assets Metadata is returned", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ReplaceVNFInfo.class)))),
1554         @ApiResponse(responseCode = "400", description = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
1555         @ApiResponse(responseCode = "401", description = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
1556         @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
1557         @ApiResponse(responseCode = "404", description = "Error: Requested '%1' (uuid) resource was not found - SVC4063"),
1558         @ApiResponse(responseCode = "405", description = "Method  Not Allowed  :  Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
1559         @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"),
1560         @ApiResponse(responseCode = "409", description = "Service already exist")})
1561     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
1562     public Response replaceVNF(@Parameter(description = "The user id", required = true) @HeaderParam(value = Constants.USER_ID_HEADER) String userId,
1563                                @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
1564                                @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
1565                                @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
1566                                @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
1567                                @Context final HttpServletRequest request,
1568                                @Parameter(description = "Resource object to be created", required = true) String data) {
1569         String url = request.getMethod() + " " + request.getRequestURI();
1570         log.debug("replaceVNF: Start handle request of {}", url);
1571         User modifier = new User();
1572         modifier.setUserId(userId);
1573         log.debug("replaceVNF:modifier id is {}", userId);
1574         validateNotEmptyBody(data);
1575         Either<ReplaceVNFInfo, ResponseFormat> convertResponse = parseToReplaceVNFInfo(data, modifier);
1576         if (convertResponse.isRight()) {
1577             throw new ByResponseFormatComponentException(convertResponse.right().value());
1578         }
1579         log.debug("replaceVNF:get ReplaceVNFInfo success");
1580         String containerComponentType = SERVICES;
1581         ReplaceVNFInfo replaceVNFInfo = convertResponse.left().value();
1582         String serviceUniqueId = replaceVNFInfo.getServiceUniqueId();
1583         String abstractResourceUniqueId = replaceVNFInfo.getAbstractResourceUniqueId();
1584         ComponentInstance componentInstance = replaceVNFInfo.getRealVNFComponentInstance();
1585         log.debug("replaceVNF:get ReplaceVNFInfo,serviceUniqueId:{},abstractResourceUniqueId:{}", serviceUniqueId, abstractResourceUniqueId);
1586         try {
1587             /**
1588              * delete vnf
1589              */
1590             if (componentInstanceBusinessLogic == null) {
1591                 log.debug("replaceVNF:Unsupported component type {}", containerComponentType);
1592                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
1593             }
1594             Either<ComponentInstance, ResponseFormat> componentInstanceEither = componentInstanceBusinessLogic
1595                 .deleteAbstractComponentInstance(containerComponentType, serviceUniqueId, abstractResourceUniqueId, userId);
1596             if (componentInstanceEither.isRight()) {
1597                 log.debug("replaceVNF:delete Abstract ComponentInstance field");
1598                 return buildErrorResponse(componentInstanceEither.right().value());
1599             }
1600             /**
1601              * add vnf
1602              */
1603             log.debug("replaceVNF,start add vnf");
1604             componentInstance.setInvariantName(null);
1605             componentInstance.setCreatedFrom(CreatedFrom.UI);
1606             Either<ComponentInstance, ResponseFormat> realComponentInstance = componentInstanceBusinessLogic
1607                 .createRealComponentInstance(containerComponentType, serviceUniqueId, userId, componentInstance);
1608             if (realComponentInstance.isRight()) {
1609                 log.debug("replaceVNF:filed to add vnf");
1610                 return buildErrorResponse(realComponentInstance.right().value());
1611             }
1612             ComponentInstance newComponentInstance = realComponentInstance.left().value();
1613             log.debug("replaceVNF:success to add vnf");
1614             return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), newComponentInstance);
1615         } catch (Exception e) {
1616             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("replaceVNF");
1617             log.debug("replaceVNF with exception", e);
1618             throw e;
1619         }
1620     }
1621
1622     private Either<ReplaceVNFInfo, ResponseFormat> parseToReplaceVNFInfo(String serviceJson, User user) {
1623         log.debug("enter parseToReplaceVNFInfo,get serviceJson:{}", serviceJson);
1624         return getComponentsUtils().convertJsonToObjectUsingObjectMapper(serviceJson, user, ReplaceVNFInfo.class, AuditingActionEnum.CREATE_RESOURCE,
1625             ComponentTypeEnum.SERVICE);
1626     }
1627 }