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.config.EcompErrorName;
45 import org.openecomp.sdc.exception.ResponseFormat;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.web.context.WebApplicationContext;
50 import javax.inject.Singleton;
51 import javax.servlet.ServletContext;
52 import javax.servlet.http.HttpServletRequest;
54 import javax.ws.rs.core.Context;
55 import javax.ws.rs.core.MediaType;
56 import javax.ws.rs.core.Response;
57 import java.lang.reflect.Type;
58 import java.util.HashMap;
59 import java.util.Iterator;
61 import java.util.Map.Entry;
63 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
65 @Api(value = "Resource Property Servlet", description = "Resource Property Servlet")
67 public class PropertyServlet extends BeGenericServlet {
69 private static final Logger log = LoggerFactory.getLogger(PropertyServlet.class);
72 @Path("resources/{resourceId}/properties")
73 @Consumes(MediaType.APPLICATION_JSON)
74 @Produces(MediaType.APPLICATION_JSON)
75 @ApiOperation(value = "Create Resource Property", httpMethod = "POST", notes = "Returns created resource property", response = Response.class)
76 @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
77 @ApiResponse(code = 409, message = "Resource property already exist") })
78 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,
79 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
81 ServletContext context = request.getSession().getServletContext();
83 String url = request.getMethod() + " " + request.getRequestURI();
84 log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data);
87 // convert json to PropertyDefinition
88 Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data);
89 if (either.isRight()) {
90 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value());
91 return buildErrorResponse(responseFormat);
93 Map<String, PropertyDefinition> properties = either.left().value();
94 if (properties == null || properties.size() != 1) {
95 log.info("Property conetnt is invalid - {}", data);
96 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
97 return buildErrorResponse(responseFormat);
99 Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
100 String propertyName = entry.getKey();
101 PropertyDefinition newPropertyDefinition = entry.getValue();
103 // create the new property
104 PropertyBusinessLogic businessLogic = getPropertyBL(context);
105 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.createProperty(resourceId, propertyName, newPropertyDefinition, userId);
106 if (status.isRight()) {
107 log.info("Failed to create Property. Reason - ", status.right().value());
108 return buildErrorResponse(status.right().value());
110 EntryData<String, PropertyDefinition> property = status.left().value();
111 String name = property.getKey();
112 PropertyDefinition propertyDefinition = property.getValue();
114 log.debug("Property {} created successfully with id {}", name, propertyDefinition.getUniqueId());
115 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED);
116 return buildOkResponse(responseFormat, propertyToJson(property));
118 } catch (Exception e) {
119 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property");
120 log.debug("create property failed with exception", e);
121 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
122 return buildErrorResponse(responseFormat);
128 @Path("resources/{resourceId}/properties/{propertyId}")
129 @Consumes(MediaType.APPLICATION_JSON)
130 @Produces(MediaType.APPLICATION_JSON)
131 @ApiOperation(value = "Create Resource Property", httpMethod = "GET", notes = "Returns property of resource", response = Response.class)
132 @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
133 @ApiResponse(code = 404, message = "Resource property not found") })
134 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,
135 @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
137 ServletContext context = request.getSession().getServletContext();
139 String url = request.getMethod() + " " + request.getRequestURI();
140 log.debug("Start handle request of {}, modifier id is {}", url, userId);
145 PropertyBusinessLogic businessLogic = getPropertyBL(context);
146 Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.getProperty(resourceId, propertyId, userId);
148 if (status.isRight()) {
149 log.info("Failed to get Property. Reason - ", status.right().value());
150 return buildErrorResponse(status.right().value());
152 Entry<String, PropertyDefinition> property = status.left().value();
153 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
154 return buildOkResponse(responseFormat, propertyToJson(property));
155 } catch (Exception e) {
156 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property");
157 log.debug("get property failed with exception", e);
158 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
159 return buildErrorResponse(responseFormat);
165 @Path("resources/{resourceId}/properties/{propertyId}")
166 @Consumes(MediaType.APPLICATION_JSON)
167 @Produces(MediaType.APPLICATION_JSON)
168 @ApiOperation(value = "Create Resource Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class)
169 @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
170 @ApiResponse(code = 404, message = "Resource property not found") })
171 public Response deleteProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
172 @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) {
174 ServletContext context = request.getSession().getServletContext();
176 String url = request.getMethod() + " " + request.getRequestURI();
177 log.debug("Start handle request of {} modifier id is {}", url, userId);
181 // delete the property
182 PropertyBusinessLogic businessLogic = getPropertyBL(context);
183 Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.deleteProperty(resourceId, propertyId, userId);
184 if (status.isRight()) {
185 log.debug("Failed to delete Property. Reason - ", status.right().value());
186 return buildErrorResponse(status.right().value());
188 Entry<String, PropertyDefinition> property = status.left().value();
189 String name = property.getKey();
190 PropertyDefinition propertyDefinition = property.getValue();
192 log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId());
193 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT);
194 return buildOkResponse(responseFormat, propertyToJson(property));
196 } catch (Exception e) {
197 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
198 log.debug("delete property failed with exception", e);
199 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
200 return buildErrorResponse(responseFormat);
206 @Path("resources/{resourceId}/properties/{propertyId}")
207 @Consumes(MediaType.APPLICATION_JSON)
208 @Produces(MediaType.APPLICATION_JSON)
209 @ApiOperation(value = "Update Resource Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class)
210 @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource property updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") })
211 public Response updateProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
212 @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,
213 @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
215 ServletContext context = request.getSession().getServletContext();
217 String url = request.getMethod() + " " + request.getRequestURI();
218 log.debug("Start handle request of {}", url);
221 User modifier = new User();
222 modifier.setUserId(userId);
223 log.debug("modifier id is {}", userId);
226 // convert json to PropertyDefinition
227 Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data);
228 if (either.isRight()) {
229 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value());
230 return buildErrorResponse(responseFormat);
232 Map<String, PropertyDefinition> properties = either.left().value();
233 if (properties == null || properties.size() != 1) {
234 log.info("Property conetnt is invalid - {}", data);
235 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
236 return buildErrorResponse(responseFormat);
238 Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
239 PropertyDefinition newPropertyDefinition = entry.getValue();
242 PropertyBusinessLogic businessLogic = getPropertyBL(context);
243 Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.updateProperty(resourceId, propertyId, newPropertyDefinition, userId);
244 if (status.isRight()) {
245 log.info("Failed to update Property. Reason - ", status.right().value());
246 return buildErrorResponse(status.right().value());
248 EntryData<String, PropertyDefinition> property = status.left().value();
249 PropertyDefinition propertyDefinition = property.getValue();
251 log.debug("Property id {} updated successfully ", propertyDefinition.getUniqueId());
252 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
253 return buildOkResponse(responseFormat, propertyToJson(property));
255 } catch (Exception e) {
256 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
257 log.debug("update property failed with exception", e);
258 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
259 return buildErrorResponse(responseFormat);
264 private Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String resourceId, String data) {
265 JSONParser parser = new JSONParser();
268 Map<String, PropertyDefinition> properties = new HashMap<String, PropertyDefinition>();
269 root = (JSONObject) parser.parse(data);
271 Set entrySet = root.entrySet();
272 Iterator iterator = entrySet.iterator();
273 while (iterator.hasNext()) {
274 Entry next = (Entry) iterator.next();
275 String propertyName = (String) next.getKey();
276 JSONObject value = (JSONObject) next.getValue();
277 String jsonString = value.toJSONString();
278 Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class);
279 if (convertJsonToObject.isRight()) {
280 return Either.right(convertJsonToObject.right().value());
282 PropertyDefinition propertyDefinition = convertJsonToObject.left().value();
283 String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(resourceId, (String) propertyName);
284 propertyDefinition.setUniqueId(uniqueId);
285 properties.put(propertyName, propertyDefinition);
288 return Either.left(properties);
289 } catch (ParseException e) {
290 log.info("Property conetnt is invalid - {}", data);
291 return Either.right(ActionStatus.INVALID_CONTENT);
295 private String propertyToJson(Map.Entry<String, PropertyDefinition> property) {
296 JSONObject root = new JSONObject();
297 String propertyName = property.getKey();
298 PropertyDefinition propertyDefinition = property.getValue();
299 JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition);
300 root.put(propertyName, propertyDefinitionO);
301 propertyDefinition.getType();
302 return root.toString();
305 private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) {
307 Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition);
308 if (either.isRight()) {
309 return new JSONObject();
311 String value = either.left().value();
313 JSONObject root = (JSONObject) new JSONParser().parse(value);
315 } catch (ParseException e) {
316 log.info("failed to convert input to json");
317 log.debug("failed to convert to json", e);
318 return new JSONObject();
323 private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) {
325 Type constraintType = new TypeToken<PropertyConstraint>() {
327 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create();
329 log.trace("convert json to object. json=\n {}", data);
330 t = gson.fromJson(data, clazz);
332 log.info("object is null after converting from json");
333 return Either.right(ActionStatus.INVALID_CONTENT);
335 } catch (Exception e) {
337 log.info("failed to convert from json");
338 log.debug("failed to convert from json", e);
339 return Either.right(ActionStatus.INVALID_CONTENT);
341 return Either.left(t);
344 private <T> Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) {
345 Type constraintType = new TypeToken<PropertyConstraint>() {
347 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintSerialiser()).create();
349 log.trace("convert object to json. propertyDefinition= {}", propertyDefinition);
350 String json = gson.toJson(propertyDefinition);
352 log.info("object is null after converting to json");
353 return Either.right(ActionStatus.INVALID_CONTENT);
355 return Either.left(json);
356 } catch (Exception e) {
358 log.info("failed to convert to json");
359 log.debug("failed to convert fto json", e);
360 return Either.right(ActionStatus.INVALID_CONTENT);
365 private PropertyBusinessLogic getPropertyBL(ServletContext context) {
366 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
367 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
368 PropertyBusinessLogic propertytBl = webApplicationContext.getBean(PropertyBusinessLogic.class);