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