ComponentBaseTest.java enhancement and
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / servlets / PropertyServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.sdc.be.servlets;
22
23 import java.lang.reflect.Type;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.Set;
29
30 import javax.inject.Singleton;
31 import javax.servlet.ServletContext;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.ws.rs.Consumes;
34 import javax.ws.rs.DELETE;
35 import javax.ws.rs.GET;
36 import javax.ws.rs.HeaderParam;
37 import javax.ws.rs.POST;
38 import javax.ws.rs.PUT;
39 import javax.ws.rs.Path;
40 import javax.ws.rs.PathParam;
41 import javax.ws.rs.Produces;
42 import javax.ws.rs.core.Context;
43 import javax.ws.rs.core.MediaType;
44 import javax.ws.rs.core.Response;
45
46 import org.json.simple.JSONObject;
47 import org.json.simple.parser.JSONParser;
48 import org.json.simple.parser.ParseException;
49 import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic;
50 import org.openecomp.sdc.be.config.BeEcompErrorManager;
51 import org.openecomp.sdc.be.dao.api.ActionStatus;
52 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
53 import org.openecomp.sdc.be.model.PropertyConstraint;
54 import org.openecomp.sdc.be.model.PropertyDefinition;
55 import org.openecomp.sdc.be.model.User;
56 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
57 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintSerialiser;
58 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
59 import org.openecomp.sdc.be.resources.data.EntryData;
60 import org.openecomp.sdc.common.api.Constants;
61 import org.openecomp.sdc.common.config.EcompErrorName;
62 import org.openecomp.sdc.exception.ResponseFormat;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65 import org.springframework.web.context.WebApplicationContext;
66
67 import com.google.gson.Gson;
68 import com.google.gson.GsonBuilder;
69 import com.google.gson.reflect.TypeToken;
70 import com.jcabi.aspects.Loggable;
71 import io.swagger.annotations.Api;
72 import io.swagger.annotations.ApiOperation;
73 import io.swagger.annotations.ApiParam;
74 import io.swagger.annotations.ApiResponse;
75 import io.swagger.annotations.ApiResponses;
76
77 import fj.data.Either;
78
79 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
80 @Path("/v1/catalog")
81 @Api(value = "Resource Property Servlet", description = "Resource Property Servlet")
82 @Singleton
83 public class PropertyServlet extends BeGenericServlet {
84
85         private static Logger log = LoggerFactory.getLogger(PropertyServlet.class.getName());
86
87         @POST
88         @Path("resources/{resourceId}/properties")
89         @Consumes(MediaType.APPLICATION_JSON)
90         @Produces(MediaType.APPLICATION_JSON)
91         @ApiOperation(value = "Create Resource Property", httpMethod = "POST", notes = "Returns created resource property", response = Response.class)
92         @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
93                         @ApiResponse(code = 409, message = "Resource property already exist") })
94         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,
95                         @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
96
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
102                 try {
103                         // convert json to PropertyDefinition
104                         Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data);
105                         if (either.isRight()) {
106                                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value());
107                                 return buildErrorResponse(responseFormat);
108                         }
109                         Map<String, PropertyDefinition> properties = either.left().value();
110                         if (properties == null || properties.size() != 1) {
111                                 log.info("Property conetnt is invalid - {}", data);
112                                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
113                                 return buildErrorResponse(responseFormat);
114                         }
115                         Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
116                         String propertyName = entry.getKey();
117                         PropertyDefinition newPropertyDefinition = entry.getValue();
118
119                         // create the new property
120                         PropertyBusinessLogic businessLogic = getPropertyBL(context);
121                         Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.createProperty(resourceId, propertyName, newPropertyDefinition, userId);
122                         if (status.isRight()) {
123                                 log.info("Failed to create Property. Reason - ", status.right().value());
124                                 return buildErrorResponse(status.right().value());
125                         }
126                         EntryData<String, PropertyDefinition> property = status.left().value();
127                         String name = property.getKey();
128                         PropertyDefinition propertyDefinition = property.getValue();
129
130                         log.debug("Property {} created successfully with id {}", name, propertyDefinition.getUniqueId());
131                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED);
132                         return buildOkResponse(responseFormat, propertyToJson(property));
133
134                 } catch (Exception e) {
135                         BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Create Property");
136                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property");
137                         log.debug("create property failed with exception", e);
138                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
139                         return buildErrorResponse(responseFormat);
140
141                 }
142         }
143
144         @GET
145         @Path("resources/{resourceId}/properties/{propertyId}")
146         @Consumes(MediaType.APPLICATION_JSON)
147         @Produces(MediaType.APPLICATION_JSON)
148         @ApiOperation(value = "Create Resource Property", httpMethod = "GET", notes = "Returns property of resource", response = Response.class)
149         @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
150                         @ApiResponse(code = 404, message = "Resource property not found") })
151         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,
152                         @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
153
154                 ServletContext context = request.getSession().getServletContext();
155
156                 String url = request.getMethod() + " " + request.getRequestURI();
157                 log.debug("Start handle request of {}, modifier id is {}", url, userId);
158
159                 try {
160
161                         //
162                         PropertyBusinessLogic businessLogic = getPropertyBL(context);
163                         Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.getProperty(resourceId, propertyId, userId);
164
165                         if (status.isRight()) {
166                                 log.info("Failed to get Property. Reason - ", status.right().value());
167                                 return buildErrorResponse(status.right().value());
168                         }
169                         Entry<String, PropertyDefinition> property = status.left().value();
170                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
171                         return buildOkResponse(responseFormat, propertyToJson(property));
172                 } catch (Exception e) {
173                         BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Get Property");
174                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property");
175                         log.debug("get property failed with exception", e);
176                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
177                         return buildErrorResponse(responseFormat);
178
179                 }
180         }
181
182         @DELETE
183         @Path("resources/{resourceId}/properties/{propertyId}")
184         @Consumes(MediaType.APPLICATION_JSON)
185         @Produces(MediaType.APPLICATION_JSON)
186         @ApiOperation(value = "Create Resource Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class)
187         @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"),
188                         @ApiResponse(code = 404, message = "Resource property not found") })
189         public Response deleteProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId,
190                         @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) {
191
192                 ServletContext context = request.getSession().getServletContext();
193
194                 String url = request.getMethod() + " " + request.getRequestURI();
195                 log.debug("Start handle request of {} modifier id is {}", url, userId);
196
197                 try {
198
199                         // delete the property
200                         PropertyBusinessLogic businessLogic = getPropertyBL(context);
201                         Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.deleteProperty(resourceId, propertyId, userId);
202                         if (status.isRight()) {
203                                 log.debug("Failed to delete Property. Reason - ", status.right().value());
204                                 return buildErrorResponse(status.right().value());
205                         }
206                         Entry<String, PropertyDefinition> property = status.left().value();
207                         String name = property.getKey();
208                         PropertyDefinition propertyDefinition = property.getValue();
209
210                         log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId());
211                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT);
212                         return buildOkResponse(responseFormat, propertyToJson(property));
213
214                 } catch (Exception e) {
215                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property");
216                         log.debug("delete property failed with exception", e);
217                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
218                         return buildErrorResponse(responseFormat);
219
220                 }
221         }
222
223         @PUT
224         @Path("resources/{resourceId}/properties/{propertyId}")
225         @Consumes(MediaType.APPLICATION_JSON)
226         @Produces(MediaType.APPLICATION_JSON)
227         @ApiOperation(value = "Update Resource Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class)
228         @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource property updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") })
229         public Response updateProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId,
230                         @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,
231                         @HeaderParam(value = Constants.USER_ID_HEADER) String userId) {
232
233                 ServletContext context = request.getSession().getServletContext();
234
235                 String url = request.getMethod() + " " + request.getRequestURI();
236                 log.debug("Start handle request of {}", url);
237
238                 // get modifier id
239                 User modifier = new User();
240                 modifier.setUserId(userId);
241                 log.debug("modifier id is {}", userId);
242
243                 try {
244                         // convert json to PropertyDefinition
245                         Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data);
246                         if (either.isRight()) {
247                                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value());
248                                 return buildErrorResponse(responseFormat);
249                         }
250                         Map<String, PropertyDefinition> properties = either.left().value();
251                         if (properties == null || properties.size() != 1) {
252                                 log.info("Property conetnt is invalid - {}", data);
253                                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
254                                 return buildErrorResponse(responseFormat);
255                         }
256                         Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next();
257                         PropertyDefinition newPropertyDefinition = entry.getValue();
258
259                         // update property
260                         PropertyBusinessLogic businessLogic = getPropertyBL(context);
261                         Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.updateProperty(resourceId, propertyId, newPropertyDefinition, userId);
262                         if (status.isRight()) {
263                                 log.info("Failed to update Property. Reason - ", status.right().value());
264                                 return buildErrorResponse(status.right().value());
265                         }
266                         EntryData<String, PropertyDefinition> property = status.left().value();
267                         PropertyDefinition propertyDefinition = property.getValue();
268
269                         log.debug("Property id {} updated successfully ", propertyDefinition.getUniqueId());
270                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
271                         return buildOkResponse(responseFormat, propertyToJson(property));
272
273                 } catch (Exception e) {
274                         BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeRestApiGeneralError, "Update Property");
275                         BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property");
276                         log.debug("update property failed with exception", e);
277                         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
278                         return buildErrorResponse(responseFormat);
279
280                 }
281         }
282
283         private Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String resourceId, String data) {
284                 JSONParser parser = new JSONParser();
285                 JSONObject root;
286                 try {
287                         Map<String, PropertyDefinition> properties = new HashMap<String, PropertyDefinition>();
288                         root = (JSONObject) parser.parse(data);
289
290                         Set entrySet = root.entrySet();
291                         Iterator iterator = entrySet.iterator();
292                         while (iterator.hasNext()) {
293                                 Entry next = (Entry) iterator.next();
294                                 String propertyName = (String) next.getKey();
295                                 JSONObject value = (JSONObject) next.getValue();
296                                 String jsonString = value.toJSONString();
297                                 Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class);
298                                 if (convertJsonToObject.isRight()) {
299                                         return Either.right(convertJsonToObject.right().value());
300                                 }
301                                 PropertyDefinition propertyDefinition = convertJsonToObject.left().value();
302                                 // PropertyDefinition propertyDefinition =
303                                 // gson.fromJson(jsonString , PropertyDefinition.class);
304                                 String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(resourceId, (String) propertyName);
305                                 propertyDefinition.setUniqueId(uniqueId);
306                                 properties.put(propertyName, propertyDefinition);
307                         }
308
309                         // Set keySet = root.keySet();
310                         // for (Object propertyName : keySet){
311                         // JSONObject val = (JSONObject) root.get(propertyName);
312                         // String jsonString = val.toJSONString();
313                         // Either<PropertyDefinition,ActionStatus> convertJsonToObject =
314                         // convertJsonToObject(jsonString, PropertyDefinition.class);
315                         // if (convertJsonToObject.isRight()){
316                         // return Either.right(convertJsonToObject.right().value());
317                         // }
318                         // PropertyDefinition propertyDefinition =
319                         // convertJsonToObject.left().value();
320                         // //PropertyDefinition propertyDefinition =
321                         // gson.fromJson(jsonString , PropertyDefinition.class);
322                         // String uniqueId =
323                         // UniqueIdBuilder.buildPropertyUniqueId("resourceId",
324                         // (String)propertyName);
325                         // propertyDefinition.setUniqueId(uniqueId);
326                         // properties.put((String)propertyName,propertyDefinition);
327                         // }
328                         return Either.left(properties);
329                 } catch (ParseException e) {
330                         log.info("Property conetnt is invalid - {}", data);
331                         return Either.right(ActionStatus.INVALID_CONTENT);
332                 }
333         }
334
335         private String propertyToJson(Map.Entry<String, PropertyDefinition> property) {
336                 JSONObject root = new JSONObject();
337                 String propertyName = property.getKey();
338                 PropertyDefinition propertyDefinition = property.getValue();
339                 // String jsonPropertyDefinition = gson.toJson(propertyDefinition);
340                 // root.put(propertyName, jsonPropertyDefinition);
341                 JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition);
342                 root.put(propertyName, propertyDefinitionO);
343                 propertyDefinition.getType();
344                 return root.toString();
345         }
346
347         private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) {
348
349                 Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition);
350                 if (either.isRight()) {
351                         return new JSONObject();
352                 }
353                 String value = either.left().value();
354                 try {
355                         JSONObject root = (JSONObject) new JSONParser().parse(value);
356                         return root;
357                 } catch (ParseException e) {
358                         log.info("failed to convert input to json");
359                         log.debug("failed to convert to json", e);
360                         return new JSONObject();
361                 }
362
363         }
364
365         private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) {
366                 T t = null;
367                 Type constraintType = new TypeToken<PropertyConstraint>() {
368                 }.getType();
369                 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create();
370                 try {
371                         log.trace("convert json to object. json=\n {}", data);
372                         t = gson.fromJson(data, clazz);
373                         if (t == null) {
374                                 log.info("object is null after converting from json");
375                                 return Either.right(ActionStatus.INVALID_CONTENT);
376                         }
377                 } catch (Exception e) {
378                         // INVALID JSON
379                         log.info("failed to convert from json");
380                         log.debug("failed to convert from json", e);
381                         return Either.right(ActionStatus.INVALID_CONTENT);
382                 }
383                 return Either.left(t);
384         }
385
386         private <T> Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) {
387                 Type constraintType = new TypeToken<PropertyConstraint>() {
388                 }.getType();
389                 Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintSerialiser()).create();
390                 try {
391                         log.trace("convert object to json. propertyDefinition= {}", propertyDefinition.toString());
392                         String json = gson.toJson(propertyDefinition);
393                         if (json == null) {
394                                 log.info("object is null after converting to json");
395                                 return Either.right(ActionStatus.INVALID_CONTENT);
396                         }
397                         return Either.left(json);
398                 } catch (Exception e) {
399                         // INVALID JSON
400                         log.info("failed to convert to json");
401                         log.debug("failed to convert fto json", e);
402                         return Either.right(ActionStatus.INVALID_CONTENT);
403                 }
404
405         }
406
407         private PropertyBusinessLogic getPropertyBL(ServletContext context) {
408                 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
409                 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
410                 PropertyBusinessLogic propertytBl = webApplicationContext.getBean(PropertyBusinessLogic.class);
411                 return propertytBl;
412         }
413
414         // private class UiProperty{
415         // String type;
416         // String source;
417         // String name;
418         // String description;
419         // public String getType() {
420         // return type;
421         // }
422         // public void setType(String type) {
423         // this.type = type;
424         // }
425         // public String getSource() {
426         // return source;
427         // }
428         // public void setSource(String source) {
429         // this.source = source;
430         // }
431         // public String getName() {
432         // return name;
433         // }
434         // public void setName(String name) {
435         // this.name = name;
436         // }
437         // public String getDescription() {
438         // return description;
439         // }
440         // public void setDescription(String description) {
441         // this.description = description;
442         // }
443         //
444         // }
445
446 }