9ce5674cc34a60bbf4c8960dd56259c65b7ad29f
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / servlets / ServiceConsumptionServlet.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.openecomp.sdc.be.servlets;
18
19 import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF;
20
21 import com.google.gson.Gson;
22 import com.google.gson.JsonParseException;
23 import com.jcabi.aspects.Loggable;
24
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.stream.Collectors;
32
33 import fj.data.Either;
34 import io.swagger.annotations.Api;
35 import io.swagger.annotations.ApiOperation;
36 import io.swagger.annotations.ApiParam;
37 import io.swagger.annotations.ApiResponse;
38 import io.swagger.annotations.ApiResponses;
39 import org.apache.commons.lang3.StringUtils;
40 import org.json.simple.JSONArray;
41 import org.json.simple.parser.JSONParser;
42 import org.json.simple.parser.ParseException;
43 import org.openecomp.sdc.be.components.impl.InterfaceOperationBusinessLogic;
44 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
45 import org.openecomp.sdc.be.config.BeEcompErrorManager;
46 import org.openecomp.sdc.be.dao.api.ActionStatus;
47 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
48 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
49 import org.openecomp.sdc.be.model.Operation;
50 import org.openecomp.sdc.be.model.OperationInput;
51 import org.openecomp.sdc.be.model.User;
52 import org.openecomp.sdc.be.model.tosca.ToscaFunctions;
53 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
54 import org.openecomp.sdc.be.types.ServiceConsumptionData;
55 import org.openecomp.sdc.be.types.ServiceConsumptionSource;
56 import org.openecomp.sdc.common.api.Constants;
57 import org.openecomp.sdc.exception.ResponseFormat;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 import javax.inject.Singleton;
62 import javax.servlet.ServletContext;
63 import javax.servlet.http.HttpServletRequest;
64 import javax.ws.rs.Consumes;
65 import javax.ws.rs.GET;
66 import javax.ws.rs.HeaderParam;
67 import javax.ws.rs.POST;
68 import javax.ws.rs.Path;
69 import javax.ws.rs.PathParam;
70 import javax.ws.rs.Produces;
71 import javax.ws.rs.core.Context;
72 import javax.ws.rs.core.MediaType;
73 import javax.ws.rs.core.Response;
74
75 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
76 @Path("/v1/catalog")
77 @Api(value = "Service Consumption Servlet", description = "Service Consumption Servlet")
78 @Singleton
79 public class ServiceConsumptionServlet extends BeGenericServlet {
80
81   private static final Logger log = LoggerFactory.getLogger(ServiceConsumptionServlet.class);
82
83   @POST
84   @Path("/services/{serviceId}/consumption/{serviceInstanceId}")
85   @Consumes(MediaType.APPLICATION_JSON)
86   @Produces(MediaType.APPLICATION_JSON)
87   @ApiOperation(value = "Service consumption on operation", httpMethod = "POST",
88       notes = "Returns consumption data", response = Response.class)
89       @ApiResponses(value = { @ApiResponse(code = 201, message = "Service property created"),
90       @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
91       @ApiResponse(code = 409, message = "Service property already exist") })
92   public Response addInputToServiceOperation(@PathParam("serviceId")final String serviceId,
93                                              @PathParam("serviceInstanceId")final String serviceInstanceId,
94                                              @ApiParam(value = "Service Consumption Data", required = true) String data,
95                                              @Context final HttpServletRequest request,
96                                              @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
97     ServletContext context = request.getSession().getServletContext();
98
99     String url = request.getMethod() + " " + request.getRequestURI();
100     log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
101     User modifier = new User();
102     modifier.setUserId(userId);
103
104     try {
105
106       Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> dataFromJson =
107           getServiceConsumptionData(data, modifier);
108       if(dataFromJson.isRight()) {
109         return buildErrorResponse(dataFromJson.right().value());
110       }
111
112       Map<String, List<ServiceConsumptionData>> serviceConsumptionDataMap = dataFromJson.left().value();
113       ServiceBusinessLogic serviceBL = getServiceBL(context);
114
115       for(Entry<String, List<ServiceConsumptionData>> consumptionEntry : serviceConsumptionDataMap.entrySet()) {
116         List<ServiceConsumptionData> consumptionList = consumptionEntry.getValue();
117         Either<List<Operation>, ResponseFormat> operationEither =
118             serviceBL.addServiceConsumptionData(serviceId, serviceInstanceId,
119                 consumptionEntry.getKey(), consumptionList, userId);
120         if (operationEither.isRight()) {
121           return buildErrorResponse(operationEither.right().value());
122         }
123       }
124
125       return buildOkResponse(serviceConsumptionDataMap);
126
127     }
128     catch (Exception e) {
129       BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Operation Inputs");
130       log.debug("Create Operation Inputs failed with exception", e);
131       ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
132       return buildErrorResponse(responseFormat);
133     }
134
135   }
136
137   @GET
138   @Path("/services/{serviceId}/consumption/{serviceInstanceId}/interfaces/{interfaceId}/operations/{operationId}/inputs")
139   @Consumes(MediaType.APPLICATION_JSON)
140   @Produces(MediaType.APPLICATION_JSON)
141   public Response getInputsListOfOperation(@PathParam("serviceId")final String serviceId,
142                                            @PathParam("serviceInstanceId")final String serviceInstanceId,
143                                            @PathParam("interfaceId")final String interfaceId,
144                                            @PathParam("operationId")final String operationId,
145                                            @Context final HttpServletRequest request,
146                                            @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
147
148     ServletContext context = request.getSession().getServletContext();
149
150     String url = request.getMethod() + " " + request.getRequestURI();
151     log.debug("Start handle request of {} modifier id is {}", url, userId);
152     User user = new User();
153     user.setUserId(userId);
154
155     try {
156       InterfaceOperationBusinessLogic interfaceOperationBL = getInterfaceOperationBL(context);
157       Either<List<OperationInputDefinition>, ResponseFormat> inputsEither =
158           interfaceOperationBL.getInputsListForOperation(serviceId, serviceInstanceId, interfaceId, operationId, user);
159
160       if(inputsEither.isRight()) {
161         return buildErrorResponse(inputsEither.right().value());
162       }
163
164       List<OperationInputDefinition> inputs = inputsEither.left().value();
165                 return buildOkResponse(updateOperationInputListForUi(inputs, interfaceOperationBL));
166     }
167     catch (Exception e) {
168       BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Operation Inputs");
169       log.debug("Get Operation Inputs failed with exception", e);
170       ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
171       return buildErrorResponse(responseFormat);
172     }
173   }
174
175         private List<OperationInput> updateOperationInputListForUi(List<OperationInputDefinition> inputsList,
176                                                                                                                            InterfaceOperationBusinessLogic interfaceOperationBL) {
177                 List<OperationInput> operationInputs = new ArrayList<>();
178                 for(OperationInputDefinition input : inputsList) {
179
180                         String value = input.getValue();
181
182                         // Additional UI mapping needed for other sources
183                         if (StringUtils.isNotBlank(value)
184                                         && !ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) {
185                                 uiMappingForOtherSources(value, input);
186                         }
187
188                         // Add Constraint for UI
189                         OperationInput operationInput = new OperationInput(input);
190                         operationInput.setConstraints(interfaceOperationBL.setInputConstraint(input));
191                         operationInputs.add(operationInput);
192                 }
193
194                 return operationInputs;
195         }
196
197         private void uiMappingForOtherSources(String value, OperationInputDefinition input) {
198                 try {
199                         Map<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class);
200                         String toscaFunction = valueAsMap.keySet().iterator().next();
201                         Object consumptionValueName = valueAsMap.values().iterator().next();
202                         if(consumptionValueName instanceof List) {
203                                 List<Object> toscaFunctionList = (List<Object>) consumptionValueName;
204                                 String consumptionInputValue = null;
205                                 if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) {
206                                         String propertyValue = toscaFunctionList.stream()
207                                                         .map(Object::toString)
208                                                         .filter(val -> !val.equals(SELF))
209                                                         .collect(Collectors.joining("_"));
210                                         consumptionInputValue = String.valueOf(propertyValue);
211                                 } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) {
212                                         //Return full output name
213                                         consumptionInputValue =
214                                                         toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3);
215                                 }
216                                 input.setValue(consumptionInputValue);
217                         } else {
218                                 input.setValue(String.valueOf(consumptionValueName));
219                         }
220                 }
221                 catch(JsonParseException ex){
222                         log.info("This means it is static value for which no changes are needed");
223                 }
224         }
225
226   private Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> getServiceConsumptionData(String data,
227                                                                                                       User user) {
228     JSONParser parser = new JSONParser();
229     Map<String, List<ServiceConsumptionData>> serviceConsumptionDataMap = new HashMap<>();
230
231     try {
232       JSONArray operationsArray = (JSONArray) parser.parse(data);
233       Iterator iterator = operationsArray.iterator();
234       while (iterator.hasNext()) {
235         Map next = (Map) iterator.next();
236         Entry consumptionEntry = (Entry) next.entrySet().iterator().next();
237         String operationId = (String) consumptionEntry.getKey();
238         Object value = consumptionEntry.getValue();
239
240         JSONArray inputsArray = (JSONArray) parser.parse(value.toString());
241         serviceConsumptionDataMap.putIfAbsent(operationId, new ArrayList<>());
242         for(Object consumptionObject : inputsArray) {
243           Either<ServiceConsumptionData, ResponseFormat> serviceDataEither =
244               getComponentsUtils()
245                   .convertJsonToObjectUsingObjectMapper(consumptionObject.toString(), user, ServiceConsumptionData
246                       .class, AuditingActionEnum.CREATE_RESOURCE, ComponentTypeEnum.SERVICE);
247           if(serviceDataEither.isRight()) {
248             return Either.right(serviceDataEither.right().value());
249           }
250
251           serviceConsumptionDataMap.get(operationId).add(serviceDataEither.left().value());
252         }
253       }
254     }
255     catch (ParseException e) {
256       log.info("Conetnt is invalid - {}", data);
257       return Either.right(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
258     }
259     return Either.left(serviceConsumptionDataMap);
260   }
261 }