2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.servlets;
23 import com.fasterxml.jackson.databind.DeserializationFeature;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.module.SimpleModule;
26 import com.google.gson.Gson;
27 import com.google.gson.GsonBuilder;
28 import com.google.gson.reflect.TypeToken;
29 import fj.data.Either;
30 import java.lang.reflect.Type;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
35 import java.util.Map.Entry;
36 import java.util.Objects;
38 import java.util.function.Supplier;
39 import javax.servlet.ServletContext;
40 import javax.servlet.http.HttpServletRequest;
41 import javax.ws.rs.core.Context;
42 import javax.ws.rs.core.Response;
43 import javax.ws.rs.core.Response.ResponseBuilder;
44 import org.json.simple.JSONArray;
45 import org.json.simple.JSONObject;
46 import org.json.simple.parser.JSONParser;
47 import org.json.simple.parser.ParseException;
48 import org.openecomp.sdc.be.components.impl.BaseBusinessLogic;
49 import org.openecomp.sdc.be.components.impl.InputsBusinessLogic;
50 import org.openecomp.sdc.be.components.impl.PolicyBusinessLogic;
51 import org.openecomp.sdc.be.config.BeEcompErrorManager;
52 import org.openecomp.sdc.be.dao.api.ActionStatus;
53 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
54 import org.openecomp.sdc.be.datatypes.enums.DeclarationTypeEnum;
55 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
56 import org.openecomp.sdc.be.impl.ComponentsUtils;
57 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
58 import org.openecomp.sdc.be.model.ComponentInstInputsMap;
59 import org.openecomp.sdc.be.model.PropertyConstraint;
60 import org.openecomp.sdc.be.model.PropertyDefinition;
61 import org.openecomp.sdc.be.model.User;
62 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
63 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintJacksonDeserializer;
64 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
65 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
66 import org.openecomp.sdc.be.user.UserBusinessLogic;
67 import org.openecomp.sdc.common.api.Constants;
68 import org.openecomp.sdc.common.datastructure.Wrapper;
69 import org.openecomp.sdc.common.log.wrappers.Logger;
70 import org.openecomp.sdc.common.servlets.BasicServlet;
71 import org.openecomp.sdc.exception.ResponseFormat;
72 import org.springframework.web.context.WebApplicationContext;
74 public class BeGenericServlet extends BasicServlet {
76 public BeGenericServlet(UserBusinessLogic userAdminManager,
77 ComponentsUtils componentsUtils) {
78 this.userAdminManager = userAdminManager;
79 this.componentsUtils = componentsUtils;
83 protected HttpServletRequest servletRequest;
85 private static final Logger log = Logger.getLogger(BeGenericServlet.class);
87 private static final String PROPERTY_NAME_REGEX = "[\\w,\\d,_]+";
89 private UserBusinessLogic userAdminManager;
90 protected ComponentsUtils componentsUtils;
92 /******************** New error response mechanism
93 * @param requestErrorWrapper **************/
95 protected Response buildErrorResponse(ResponseFormat requestErrorWrapper) {
96 return Response.status(requestErrorWrapper.getStatus()).entity(gson.toJson(requestErrorWrapper.getRequestError())).build();
99 protected Response buildGeneralErrorResponse() {
100 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
103 protected Response buildOkResponse(Object entity) {
104 return buildOkResponseStatic(entity);
107 private static Response buildOkResponseStatic(Object entity) {
108 return Response.status(Response.Status.OK)
113 protected Response buildOkResponse(ResponseFormat errorResponseWrapper, Object entity) {
114 return buildOkResponse(errorResponseWrapper, entity, null);
117 protected Response buildOkResponse(ResponseFormat errorResponseWrapper, Object entity, Map<String, String> additionalHeaders) {
118 int status = errorResponseWrapper.getStatus();
119 ResponseBuilder responseBuilder = Response.status(status);
120 if (entity != null) {
121 if (log.isTraceEnabled())
122 log.trace("returned entity is {}", entity.toString());
123 responseBuilder = responseBuilder.entity(entity);
125 if (additionalHeaders != null) {
126 for (Entry<String, String> additionalHeader : additionalHeaders.entrySet()) {
127 String headerName = additionalHeader.getKey();
128 String headerValue = additionalHeader.getValue();
129 if (log.isTraceEnabled())
130 log.trace("Adding header {} with value {} to the response", headerName, headerValue);
131 responseBuilder.header(headerName, headerValue);
134 return responseBuilder.build();
137 /*******************************************************************************************************/
138 protected Either<User, ResponseFormat> getUser(final HttpServletRequest request, String userId) {
139 Either<User, ActionStatus> eitherCreator = userAdminManager.getUser(userId, false);
140 if (eitherCreator.isRight()) {
141 log.info("createResource method - user is not listed. userId= {}", userId);
142 ResponseFormat errorResponse = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_INFORMATION);
143 User user = new User("", "", userId, "", null, null);
145 getComponentsUtils().auditResource(errorResponse, user, "", AuditingActionEnum.CHECKOUT_RESOURCE);
146 return Either.right(errorResponse);
148 return Either.left(eitherCreator.left().value());
152 <T> T getClassFromWebAppContext(ServletContext context, Supplier<Class<T>> businessLogicClassGen) {
153 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
154 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
155 return webApplicationContext.getBean(businessLogicClassGen.get());
158 protected ComponentsUtils getComponentsUtils() {
159 return componentsUtils;
163 * Used to support Unit Test.<br>
164 * Header Params are not supported in Unit Tests
168 String initHeaderParam(String headerValue, HttpServletRequest request, String headerName) {
170 if (headerValue != null) {
171 retValue = headerValue;
173 retValue = request.getHeader(headerName);
178 protected String getContentDispositionValue(String artifactFileName) {
179 return new StringBuilder().append("attachment; filename=\"").append(artifactFileName).append("\"").toString();
182 <T> void convertJsonToObjectOfClass(String json, Wrapper<T> policyWrapper, Class<T> clazz, Wrapper<Response> errorWrapper) {
184 ObjectMapper mapper = new ObjectMapper()
185 .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
186 .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
188 log.trace("Starting to convert json to object. Json=\n{}", json);
190 SimpleModule module = new SimpleModule("customDeserializationModule");
191 module.addDeserializer(PropertyConstraint.class, new PropertyConstraintJacksonDeserializer());
192 mapper.registerModule(module);
194 object = mapper.readValue(json, clazz);
195 if (object != null) {
196 policyWrapper.setInnerElement(object);
198 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
199 log.debug("The object of class {} is null after converting from json. ", clazz);
200 errorWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)));
202 } catch (Exception e) {
203 BeEcompErrorManager.getInstance().logBeInvalidJsonInput("convertJsonToObject");
204 log.debug("The exception {} occured upon json to object convertation. Json=\n{}", e, json);
205 errorWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)));
209 protected Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String componentId, String data) {
210 JSONParser parser = new JSONParser();
213 Map<String, PropertyDefinition> properties = new HashMap<>();
214 root = (JSONObject) parser.parse(data);
216 Set entrySet = root.entrySet();
217 Iterator iterator = entrySet.iterator();
218 while (iterator.hasNext()) {
219 Entry next = (Entry) iterator.next();
220 String propertyName = (String) next.getKey();
222 if(!isPropertyNameValid(propertyName)) {
223 return Either.right(ActionStatus.INVALID_PROPERTY_NAME);
226 JSONObject value = (JSONObject) next.getValue();
227 Either<PropertyDefinition, ActionStatus> propertyDefinitionEither =
228 getPropertyDefinitionFromJson(componentId, propertyName, value);
230 if(propertyDefinitionEither.isRight()) {
231 return Either.right(propertyDefinitionEither.right().value());
234 properties.put(propertyName, propertyDefinitionEither.left().value());
237 return Either.left(properties);
238 } catch (ParseException e) {
239 log.info("Property conetnt is invalid - {}", data);
240 return Either.right(ActionStatus.INVALID_CONTENT);
244 protected boolean isPropertyNameValid(String propertyName) {
245 return Objects.nonNull(propertyName)
246 && propertyName.matches(PROPERTY_NAME_REGEX);
250 private Either<PropertyDefinition, ActionStatus> getPropertyDefinitionFromJson(String componentId, String propertyName, JSONObject value) {
251 String jsonString = value.toJSONString();
252 Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class);
253 if (convertJsonToObject.isRight()) {
254 return Either.right(convertJsonToObject.right().value());
256 PropertyDefinition propertyDefinition = convertJsonToObject.left().value();
257 String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(componentId, propertyName);
258 propertyDefinition.setUniqueId(uniqueId);
260 return Either.left(propertyDefinition);
263 protected Either<Map<String, PropertyDefinition>, ActionStatus> getPropertiesListForUpdate(String data) {
265 Map<String, PropertyDefinition> properties = new HashMap<>();
266 JSONParser parser = new JSONParser();
270 jsonArray = (JSONArray) parser.parse(data);
271 for (Object jsonElement : jsonArray) {
272 String propertyAsString = jsonElement.toString();
273 Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(propertyAsString, PropertyDefinition.class);
275 if (convertJsonToObject.isRight()) {
276 return Either.right(convertJsonToObject.right().value());
279 PropertyDefinition propertyDefinition = convertJsonToObject.left().value();
280 properties.put(propertyDefinition.getName(), propertyDefinition);
283 return Either.left(properties);
284 } catch (Exception e) {
285 log.info("Property content is invalid - {}", data);
286 return Either.right(ActionStatus.INVALID_CONTENT);
292 protected String propertyToJson(Map.Entry<String, PropertyDefinition> property) {
293 JSONObject root = new JSONObject();
294 String propertyName = property.getKey();
295 PropertyDefinition propertyDefinition = property.getValue();
296 JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition);
297 root.put(propertyName, propertyDefinitionO);
298 propertyDefinition.getType();
299 return root.toString();
302 private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) {
304 Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition);
305 if (either.isRight()) {
306 return new JSONObject();
308 String value = either.left().value();
310 JSONObject root = (JSONObject) new JSONParser().parse(value);
312 } catch (ParseException e) {
313 log.info("failed to convert input to json");
314 log.error("failed to convert to json", e);
315 return new JSONObject();
320 protected <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) {
322 Type constraintType = new TypeToken<PropertyConstraint>() {
325 gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyOperation.PropertyConstraintDeserialiser()).create();
327 log.trace("convert json to object. json=\n {}", data);
328 t = gson.fromJson(data, clazz);
330 log.info("object is null after converting from json");
331 return Either.right(ActionStatus.INVALID_CONTENT);
333 } catch (Exception e) {
335 log.info("failed to convert from json");
336 log.error("failed to convert from json", e);
337 return Either.right(ActionStatus.INVALID_CONTENT);
339 return Either.left(t);
342 private Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) {
343 Type constraintType = new TypeToken<PropertyConstraint>() {
345 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyOperation.PropertyConstraintSerialiser()).create();
347 log.trace("convert object to json. propertyDefinition= {}", propertyDefinition);
348 String json = gson.toJson(propertyDefinition);
350 log.info("object is null after converting to json");
351 return Either.right(ActionStatus.INVALID_CONTENT);
353 return Either.left(json);
354 } catch (Exception e) {
356 log.info("failed to convert to json");
357 log.debug("failed to convert fto json", e);
358 return Either.right(ActionStatus.INVALID_CONTENT);
363 protected InputsBusinessLogic getInputBL(ServletContext context) {
364 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
365 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
366 return webApplicationContext.getBean(InputsBusinessLogic.class);
369 protected PolicyBusinessLogic getPolicyBL(ServletContext context) {
370 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
371 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
372 return webApplicationContext.getBean(PolicyBusinessLogic.class);
375 protected Either<ComponentInstInputsMap, ResponseFormat> parseToComponentInstanceMap(String componentJson, User user, ComponentTypeEnum componentType) {
376 return getComponentsUtils().convertJsonToObjectUsingObjectMapper(componentJson, user, ComponentInstInputsMap.class, AuditingActionEnum.CREATE_RESOURCE, componentType);
379 protected Response declareProperties(String userId, String componentId, String componentType,
380 String componentInstInputsMapObj, DeclarationTypeEnum typeEnum, HttpServletRequest request) {
381 ServletContext context = request.getSession().getServletContext();
382 String url = request.getMethod() + " " + request.getRequestURI();
383 log.debug("(get) Start handle request of {}", url);
384 Response response = null;
387 BaseBusinessLogic businessLogic = getBlForPropertyDeclaration(typeEnum, context);
390 User modifier = new User();
391 modifier.setUserId(userId);
392 log.debug("modifier id is {}", userId);
393 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
394 Either<ComponentInstInputsMap, ResponseFormat> componentInstInputsMapRes = parseToComponentInstanceMap(componentInstInputsMapObj, modifier, componentTypeEnum);
395 if (componentInstInputsMapRes.isRight()) {
396 log.debug("failed to parse componentInstInputsMap");
397 response = buildErrorResponse(componentInstInputsMapRes.right().value());
401 Either<List<ToscaDataDefinition>, ResponseFormat> propertiesAfterDeclaration = businessLogic
402 .declareProperties(userId, componentId,
404 componentInstInputsMapRes.left().value());
405 if (propertiesAfterDeclaration.isRight()) {
406 log.debug("failed to create inputs for service: {}", componentId);
407 return buildErrorResponse(propertiesAfterDeclaration.right().value());
409 Object properties = RepresentationUtils.toRepresentation(propertiesAfterDeclaration.left().value());
410 return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), properties);
412 } catch (Exception e) {
413 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create inputs for service with id: " + componentId);
414 log.debug("Properties declaration failed with exception", e);
415 response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
420 public BaseBusinessLogic getBlForPropertyDeclaration(DeclarationTypeEnum typeEnum,
421 ServletContext context) {
422 if(typeEnum.equals(DeclarationTypeEnum.POLICY)) {
423 return getPolicyBL(context);
426 return getInputBL(context);