2 * Copyright © 2016-2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.openecomp.sdc.be.servlets;
19 import com.google.gson.Gson;
20 import com.google.gson.JsonParseException;
21 import com.jcabi.aspects.Loggable;
22 import fj.data.Either;
23 import io.swagger.v3.oas.annotations.OpenAPIDefinition;
24 import io.swagger.v3.oas.annotations.Parameter;
25 import io.swagger.v3.oas.annotations.info.Info;
26 import io.swagger.v3.oas.annotations.media.ArraySchema;
27 import io.swagger.v3.oas.annotations.media.Content;
28 import io.swagger.v3.oas.annotations.media.Schema;
29 import io.swagger.v3.oas.annotations.responses.ApiResponse;
30 import io.swagger.v3.oas.annotations.responses.ApiResponses;
31 import org.apache.commons.lang3.StringUtils;
32 import org.json.simple.JSONArray;
33 import org.json.simple.parser.JSONParser;
34 import org.json.simple.parser.ParseException;
35 import org.openecomp.sdc.be.components.impl.InterfaceOperationBusinessLogic;
36 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
37 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
38 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
39 import org.openecomp.sdc.be.config.BeEcompErrorManager;
40 import org.openecomp.sdc.be.dao.api.ActionStatus;
41 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
42 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
43 import org.openecomp.sdc.be.impl.ComponentsUtils;
44 import org.openecomp.sdc.be.model.Operation;
45 import org.openecomp.sdc.be.model.OperationInput;
46 import org.openecomp.sdc.be.model.User;
47 import org.openecomp.sdc.be.model.tosca.ToscaFunctions;
48 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
49 import org.openecomp.sdc.be.types.ServiceConsumptionData;
50 import org.openecomp.sdc.be.types.ServiceConsumptionSource;
51 import org.openecomp.sdc.be.user.UserBusinessLogic;
52 import org.openecomp.sdc.common.api.Constants;
53 import org.openecomp.sdc.exception.ResponseFormat;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import javax.inject.Inject;
58 import javax.inject.Singleton;
59 import javax.servlet.http.HttpServletRequest;
60 import javax.ws.rs.Consumes;
61 import javax.ws.rs.GET;
62 import javax.ws.rs.HeaderParam;
63 import javax.ws.rs.POST;
64 import javax.ws.rs.Path;
65 import javax.ws.rs.PathParam;
66 import javax.ws.rs.Produces;
67 import javax.ws.rs.core.Context;
68 import javax.ws.rs.core.MediaType;
69 import javax.ws.rs.core.Response;
70 import java.util.ArrayList;
71 import java.util.HashMap;
72 import java.util.Iterator;
73 import java.util.List;
75 import java.util.Map.Entry;
76 import java.util.stream.Collectors;
78 import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF;
80 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
82 @OpenAPIDefinition(info = @Info(title = "Service Consumption Servlet", description = "Service Consumption Servlet"))
84 public class ServiceConsumptionServlet extends BeGenericServlet {
86 private static final Logger log = LoggerFactory.getLogger(ServiceConsumptionServlet.class);
87 private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
88 private final ServiceBusinessLogic serviceBusinessLogic;
91 public ServiceConsumptionServlet(UserBusinessLogic userBusinessLogic, ComponentsUtils componentsUtils,
92 InterfaceOperationBusinessLogic interfaceOperationBusinessLogic,
93 ServiceBusinessLogic serviceBusinessLogic) {
94 super(userBusinessLogic, componentsUtils);
95 this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic;
96 this.serviceBusinessLogic = serviceBusinessLogic;
100 @Path("/services/{serviceId}/consumption/{serviceInstanceId}")
101 @Consumes(MediaType.APPLICATION_JSON)
102 @Produces(MediaType.APPLICATION_JSON)
103 @io.swagger.v3.oas.annotations.Operation(description = "Service consumption on operation", method = "POST",
104 summary = "Returns consumption data", responses = @ApiResponse(
105 content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))))
106 @ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Service property created"),
107 @ApiResponse(responseCode = "403", description = "Restricted operation"),
108 @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
109 @ApiResponse(responseCode = "409", description = "Service property already exist")})
110 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
111 public Response addInputToServiceOperation(@PathParam("serviceId") final String serviceId,
112 @PathParam("serviceInstanceId") final String serviceInstanceId,
113 @Parameter(description = "Service Consumption Data", required = true) String data,
114 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
116 String url = request.getMethod() + " " + request.getRequestURI();
117 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
118 User modifier = new User();
119 modifier.setUserId(userId);
123 Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> dataFromJson =
124 getServiceConsumptionData(data, modifier);
125 if(dataFromJson.isRight()) {
126 return buildErrorResponse(dataFromJson.right().value());
129 Map<String, List<ServiceConsumptionData>> serviceConsumptionDataMap = dataFromJson.left().value();
131 for(Entry<String, List<ServiceConsumptionData>> consumptionEntry : serviceConsumptionDataMap.entrySet()) {
132 List<ServiceConsumptionData> consumptionList = consumptionEntry.getValue();
133 Either<List<Operation>, ResponseFormat> operationEither =
134 serviceBusinessLogic.addServiceConsumptionData(serviceId, serviceInstanceId,
135 consumptionEntry.getKey(), consumptionList, userId);
136 if (operationEither.isRight()) {
137 return buildErrorResponse(operationEither.right().value());
141 return buildOkResponse(serviceConsumptionDataMap);
144 catch (Exception e) {
145 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Operation Inputs");
146 log.debug("Create Operation Inputs failed with exception", e);
147 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
148 return buildErrorResponse(responseFormat);
154 @Path("/services/{serviceId}/consumption/{serviceInstanceId}/interfaces/{interfaceId}/operations/{operationId}/inputs")
155 @Consumes(MediaType.APPLICATION_JSON)
156 @Produces(MediaType.APPLICATION_JSON)
157 @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
158 public Response getInputsListOfOperation(@PathParam("serviceId") final String serviceId,
159 @PathParam("serviceInstanceId") final String serviceInstanceId,
160 @PathParam("interfaceId") final String interfaceId, @PathParam("operationId") final String operationId,
161 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
163 String url = request.getMethod() + " " + request.getRequestURI();
164 log.debug("Start handle request of {} modifier id is {}", url, userId);
165 User user = new User();
166 user.setUserId(userId);
169 Either<List<OperationInputDefinition>, ResponseFormat> inputsEither =
170 interfaceOperationBusinessLogic.getInputsListForOperation(serviceId, serviceInstanceId, interfaceId, operationId, user);
172 if(inputsEither.isRight()) {
173 return buildErrorResponse(inputsEither.right().value());
176 List<OperationInputDefinition> inputs = inputsEither.left().value();
177 return buildOkResponse(updateOperationInputListForUi(inputs, interfaceOperationBusinessLogic));
179 catch (Exception e) {
180 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Operation Inputs");
181 log.debug("Get Operation Inputs failed with exception", e);
182 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
183 return buildErrorResponse(responseFormat);
187 private List<OperationInput> updateOperationInputListForUi(List<OperationInputDefinition> inputsList,
188 InterfaceOperationBusinessLogic interfaceOperationBL) {
189 List<OperationInput> operationInputs = new ArrayList<>();
190 for(OperationInputDefinition input : inputsList) {
192 String value = input.getValue();
194 // Additional UI mapping needed for other sources
195 if (StringUtils.isNotBlank(value)
196 && !ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) {
197 uiMappingForOtherSources(value, input);
200 // Add Constraint for UI
201 OperationInput operationInput = new OperationInput(input);
202 operationInput.setConstraints(interfaceOperationBL.setInputConstraint(input));
203 operationInputs.add(operationInput);
206 return operationInputs;
209 private void uiMappingForOtherSources(String value, OperationInputDefinition input) {
211 Map<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class);
212 String toscaFunction = valueAsMap.keySet().iterator().next();
213 Object consumptionValueName = valueAsMap.values().iterator().next();
214 if(consumptionValueName instanceof List) {
215 List<Object> toscaFunctionList = (List<Object>) consumptionValueName;
216 String consumptionInputValue = null;
217 if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) {
218 String propertyValue = toscaFunctionList.stream()
219 .map(Object::toString)
220 .filter(val -> !val.equals(SELF))
221 .collect(Collectors.joining("_"));
222 consumptionInputValue = String.valueOf(propertyValue);
223 } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) {
224 //Return full output name
225 consumptionInputValue =
226 toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3);
228 input.setValue(consumptionInputValue);
230 input.setValue(String.valueOf(consumptionValueName));
233 catch(JsonParseException ex){
234 log.info("This means it is static value for which no changes are needed");
238 private Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> getServiceConsumptionData(String data,
240 JSONParser parser = new JSONParser();
241 Map<String, List<ServiceConsumptionData>> serviceConsumptionDataMap = new HashMap<>();
244 JSONArray operationsArray = (JSONArray) parser.parse(data);
245 Iterator iterator = operationsArray.iterator();
246 while (iterator.hasNext()) {
247 Map next = (Map) iterator.next();
248 Entry consumptionEntry = (Entry) next.entrySet().iterator().next();
249 String operationId = (String) consumptionEntry.getKey();
250 Object value = consumptionEntry.getValue();
252 JSONArray inputsArray = (JSONArray) parser.parse(value.toString());
253 serviceConsumptionDataMap.putIfAbsent(operationId, new ArrayList<>());
254 for(Object consumptionObject : inputsArray) {
255 Either<ServiceConsumptionData, ResponseFormat> serviceDataEither =
257 .convertJsonToObjectUsingObjectMapper(consumptionObject.toString(), user, ServiceConsumptionData
258 .class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE);
259 if(serviceDataEither.isRight()) {
260 return Either.right(serviceDataEither.right().value());
263 serviceConsumptionDataMap.get(operationId).add(serviceDataEither.left().value());
267 catch (ParseException e) {
268 log.info("Conetnt is invalid - {}", data);
269 return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
271 return Either.left(serviceConsumptionDataMap);