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.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import com.google.gson.reflect.TypeToken;
26 import com.jcabi.aspects.Loggable;
27 import fj.data.Either;
28 import io.swagger.annotations.*;
29 import org.json.simple.JSONObject;
30 import org.json.simple.parser.JSONParser;
31 import org.json.simple.parser.ParseException;
32 import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic;
33 import org.openecomp.sdc.be.config.BeEcompErrorManager;
34 import org.openecomp.sdc.be.dao.api.ActionStatus;
35 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
36 import org.openecomp.sdc.be.model.PropertyConstraint;
37 import org.openecomp.sdc.be.model.PropertyDefinition;
38 import org.openecomp.sdc.be.model.User;
39 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
40 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintSerialiser;
41 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
42 import org.openecomp.sdc.be.resources.data.EntryData;
43 import org.openecomp.sdc.common.api.Constants;
44 import org.openecomp.sdc.common.log.wrappers.Logger;
45 import org.openecomp.sdc.exception.ResponseFormat;
46 import org.springframework.web.context.WebApplicationContext;
48 import javax.inject.Singleton;
49 import javax.servlet.ServletContext;
50 import javax.servlet.http.HttpServletRequest;
52 import javax.ws.rs.core.Context;
53 import javax.ws.rs.core.MediaType;
54 import javax.ws.rs.core.Response;
55 import java.lang.reflect.Type;
56 import java.util.HashMap;
57 import java.util.Iterator;
59 import java.util.Map.Entry;
62 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
64 @Api(value = "Resource Property Servlet", description = "Resource Property Servlet")
66 public class PropertyServlet extends BeGenericServlet {
68 private static final Logger log = Logger.getLogger(PropertyServlet.class.getName());
71 @Path("resources/{resourceId}/properties")
72 @Consumes(MediaType.APPLICATION_JSON)
73 @Produces(MediaType.APPLICATION_JSON)
74 @ApiOperation(value = "Create Resource Property", httpMethod = "POST", notes = "Returns created resource property", response = Response.class)
75 @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
76 @ApiResponse(code = 409, message = "Resource property already exist") })
77 public Response createProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "Resource property to be created", required = true) String data,
78 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
80 ServletContext context = request.getSession().getServletContext();
82 String url = request.getMethod() + " " + request.getRequestURI();
83 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
86 // convert json to PropertyDefinition
87 Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data);
88 if (either.isRight()) {
89 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value());
90 return buildErrorResponse(responseFormat);
92 Map<String, PropertyDefinition> properties = either.left().value();
93 if (properties == null || properties.size() != 1) {
94 log.info("Property conetnt is invalid - {}", data);
95 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
96 return buildErrorResponse(responseFormat);
98 Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
99 String propertyName = entry.getKey();
100 PropertyDefinition newPropertyDefinition = entry.getValue();
102 // create the new property
103 PropertyBusinessLogic businessLogic = getPropertyBL(context);
104 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.createProperty(resourceId, propertyName, newPropertyDefinition, userId);
105 if (status.isRight()) {
106 log.info("Failed to create Property. Reason - ", status.right().value());
107 return buildErrorResponse(status.right().value());
109 EntryData<String, PropertyDefinition> property = status.left().value();
110 String name = property.getKey();
111 PropertyDefinition propertyDefinition = property.getValue();
113 log.debug("Property {} created successfully with id {}", name, propertyDefinition.getUniqueId());
114 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED);
115 return buildOkResponse(responseFormat, propertyToJson(property));
117 } catch (Exception e) {
118 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property");
119 log.debug("create property failed with exception", e);
120 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
121 return buildErrorResponse(responseFormat);
127 @Path("resources/{resourceId}/properties/{propertyId}")
128 @Consumes(MediaType.APPLICATION_JSON)
129 @Produces(MediaType.APPLICATION_JSON)
130 @ApiOperation(value = "Create Resource Property", httpMethod = "GET", notes = "Returns property of resource", response = Response.class)
131 @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
132 @ApiResponse(code = 404, message = "Resource property not found") })
133 public Response getProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "proerty id to get", required = true) @PathParam("propertyId") final String propertyId,
134 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
136 ServletContext context = request.getSession().getServletContext();
138 String url = request.getMethod() + " " + request.getRequestURI();
139 log.debug("Start handle request of {}, modifier id is {}", url, userId);
144 PropertyBusinessLogic businessLogic = getPropertyBL(context);
145 Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.getProperty(resourceId, propertyId, userId);
147 if (status.isRight()) {
148 log.info("Failed to get Property. Reason - ", status.right().value());
149 return buildErrorResponse(status.right().value());
151 Entry<String, PropertyDefinition> property = status.left().value();
152 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
153 return buildOkResponse(responseFormat, propertyToJson(property));
154 } catch (Exception e) {
155 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property");
156 log.debug("get property failed with exception", e);
157 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
158 return buildErrorResponse(responseFormat);
164 @Path("resources/{resourceId}/properties/{propertyId}")
165 @Consumes(MediaType.APPLICATION_JSON)
166 @Produces(MediaType.APPLICATION_JSON)
167 @ApiOperation(value = "Create Resource Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class)
168 @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
169 @ApiResponse(code = 404, message = "Resource property not found") })
170 public Response deleteProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
171 @ApiParam(value = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
173 ServletContext context = request.getSession().getServletContext();
175 String url = request.getMethod() + " " + request.getRequestURI();
176 log.debug("Start handle request of {} modifier id is {}", url, userId);
180 // delete the property
181 PropertyBusinessLogic businessLogic = getPropertyBL(context);
182 Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.deleteProperty(resourceId, propertyId, userId);
183 if (status.isRight()) {
184 log.debug("Failed to delete Property. Reason - ", status.right().value());
185 return buildErrorResponse(status.right().value());
187 Entry<String, PropertyDefinition> property = status.left().value();
188 String name = property.getKey();
189 PropertyDefinition propertyDefinition = property.getValue();
191 log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId());
192 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT);
193 return buildOkResponse(responseFormat, propertyToJson(property));
195 } catch (Exception e) {
196 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
197 log.debug("delete property failed with exception", e);
198 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
199 return buildErrorResponse(responseFormat);
205 @Path("resources/{resourceId}/properties/{propertyId}")
206 @Consumes(MediaType.APPLICATION_JSON)
207 @Produces(MediaType.APPLICATION_JSON)
208 @ApiOperation(value = "Update Resource Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class)
209 @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource property updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") })
210 public Response updateProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
211 @ApiParam(value = "proerty id to update", required = true) @PathParam("propertyId") final String propertyId, @ApiParam(value = "Resource property to update", required = true) String data, @Context final HttpServletRequest request,
212 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
214 ServletContext context = request.getSession().getServletContext();
216 String url = request.getMethod() + " " + request.getRequestURI();
217 log.debug("Start handle request of {}", url);
220 User modifier = new User();
221 modifier.setUserId(userId);
222 log.debug("modifier id is {}", userId);
225 // convert json to PropertyDefinition
226 Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data);
227 if (either.isRight()) {
228 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value());
229 return buildErrorResponse(responseFormat);
231 Map<String, PropertyDefinition> properties = either.left().value();
232 if (properties == null || properties.size() != 1) {
233 log.info("Property conetnt is invalid - {}", data);
234 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
235 return buildErrorResponse(responseFormat);
237 Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
238 PropertyDefinition newPropertyDefinition = entry.getValue();
241 PropertyBusinessLogic businessLogic = getPropertyBL(context);
242 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.updateProperty(resourceId, propertyId, newPropertyDefinition, userId);
243 if (status.isRight()) {
244 log.info("Failed to update Property. Reason - ", status.right().value());
245 return buildErrorResponse(status.right().value());
247 EntryData<String, PropertyDefinition> property = status.left().value();
248 PropertyDefinition propertyDefinition = property.getValue();
250 log.debug("Property id {} updated successfully ", propertyDefinition.getUniqueId());
251 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
252 return buildOkResponse(responseFormat, propertyToJson(property));
254 } catch (Exception e) {
255 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
256 log.debug("update property failed with exception", e);
257 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
258 return buildErrorResponse(responseFormat);
263 private Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String resourceId, String data) {
264 JSONParser parser = new JSONParser();
267 Map<String, PropertyDefinition> properties = new HashMap<>();
268 root = (JSONObject) parser.parse(data);
270 Set entrySet = root.entrySet();
271 Iterator iterator = entrySet.iterator();
272 while (iterator.hasNext()) {
273 Entry next = (Entry) iterator.next();
274 String propertyName = (String) next.getKey();
275 JSONObject value = (JSONObject) next.getValue();
276 String jsonString = value.toJSONString();
277 Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class);
278 if (convertJsonToObject.isRight()) {
279 return Either.right(convertJsonToObject.right().value());
281 PropertyDefinition propertyDefinition = convertJsonToObject.left().value();
282 String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(resourceId, (String) propertyName);
283 propertyDefinition.setUniqueId(uniqueId);
284 properties.put(propertyName, propertyDefinition);
287 return Either.left(properties);
288 } catch (ParseException e) {
289 log.info("Property conetnt is invalid - {}", data);
290 return Either.right(ActionStatus.INVALID_CONTENT);
294 private String propertyToJson(Map.Entry<String, PropertyDefinition> property) {
295 JSONObject root = new JSONObject();
296 String propertyName = property.getKey();
297 PropertyDefinition propertyDefinition = property.getValue();
298 JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition);
299 root.put(propertyName, propertyDefinitionO);
300 propertyDefinition.getType();
301 return root.toString();
304 private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) {
306 Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition);
307 if (either.isRight()) {
308 return new JSONObject();
310 String value = either.left().value();
312 return (JSONObject) new JSONParser().parse(value);
313 } catch (ParseException e) {
314 log.info("failed to convert input to json");
315 log.debug("failed to convert to json", e);
316 return new JSONObject();
321 private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) {
323 Type constraintType = new TypeToken<PropertyConstraint>() {
325 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new 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.debug("failed to convert from json", e);
337 return Either.right(ActionStatus.INVALID_CONTENT);
339 return Either.left(t);
342 private <T> Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) {
343 Type constraintType = new TypeToken<PropertyConstraint>() {
345 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new 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 private PropertyBusinessLogic getPropertyBL(ServletContext context) {
364 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
365 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
366 return webApplicationContext.getBean(PropertyBusinessLogic.class);