fixed some issues from sonar
[portal.git] / ecomp-portal-BE-common / src / main / java / org / onap / portalapp / portal / controller / SharedContextRestController.java
1 /*-
2  * ============LICENSE_START==========================================
3  * ONAP Portal
4  * ===================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ===================================================================
7  *
8  * Unless otherwise specified, all software contained herein is licensed
9  * under the Apache License, Version 2.0 (the "License");
10  * you may not use this software except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *             http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Unless otherwise specified, all documentation contained herein is licensed
22  * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
23  * you may not use this documentation except in compliance with the License.
24  * You may obtain a copy of the License at
25  *
26  *             https://creativecommons.org/licenses/by/4.0/
27  *
28  * Unless required by applicable law or agreed to in writing, documentation
29  * distributed under the License is distributed on an "AS IS" BASIS,
30  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  * See the License for the specific language governing permissions and
32  * limitations under the License.
33  *
34  * ============LICENSE_END============================================
35  *
36  * 
37  */
38 package org.onap.portalapp.portal.controller;
39
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.List;
44 import java.util.Map;
45
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletResponse;
48
49 import org.onap.portalapp.controller.EPRestrictedRESTfulBaseController;
50 import org.onap.portalapp.portal.domain.SharedContext;
51 import org.onap.portalapp.portal.exceptions.NotValidDataException;
52 import org.onap.portalapp.portal.logging.aop.EPAuditLog;
53 import org.onap.portalapp.portal.service.SharedContextService;
54 import org.onap.portalapp.portal.utils.EPCommonSystemProperties;
55 import org.onap.portalapp.portal.utils.PortalConstants;
56 import org.onap.portalapp.validation.DataValidator;
57 import org.onap.portalapp.validation.SecureString;
58 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
59 import org.springframework.beans.factory.annotation.Autowired;
60 import org.springframework.context.annotation.Configuration;
61 import org.springframework.context.annotation.EnableAspectJAutoProxy;
62 import org.springframework.http.HttpStatus;
63 import org.springframework.web.bind.annotation.ExceptionHandler;
64 import org.springframework.web.bind.annotation.RequestBody;
65 import org.springframework.web.bind.annotation.RequestMapping;
66 import org.springframework.web.bind.annotation.GetMapping;
67 import org.springframework.web.bind.annotation.PostMapping;
68 import org.springframework.web.bind.annotation.RequestMethod;
69 import org.springframework.web.bind.annotation.RequestParam;
70 import org.springframework.web.bind.annotation.RestController;
71
72 import com.fasterxml.jackson.core.JsonProcessingException;
73 import com.fasterxml.jackson.databind.ObjectMapper;
74
75 import io.swagger.annotations.ApiOperation;
76
77 /**
78  * The shared-context feature allows onboarded applications to share data among
79  * themselves easily for a given session. It basically implements a Java map:
80  * put or get a key-value pair within a map identified by a session ID.
81  * 
82  * This REST endpoint listens on the Portal app server and answers requests made
83  * by back-end application servers. Reads and writes values to the database
84  * using a Hibernate service to ensure all servers in a high-availability
85  * cluster see the same data.
86  */
87 @Configuration
88 @RestController
89 @RequestMapping(PortalConstants.REST_AUX_API + "/context")
90 @EnableAspectJAutoProxy
91 @EPAuditLog
92 public class SharedContextRestController extends EPRestrictedRESTfulBaseController {
93         private static final DataValidator dataValidator = new DataValidator();
94         private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SharedContextRestController.class);
95         private static final ObjectMapper mapper = new ObjectMapper();
96
97         private SharedContextService contextService;
98
99         @Autowired
100         public SharedContextRestController(SharedContextService contextService) {
101                 this.contextService = contextService;
102         }
103
104         /**
105          * Gets a value for the specified context and key (RESTful service method).
106          *
107          * @param request
108          *            HTTP servlet request
109          * @param context_id
110          *            ID that identifies the context, usually the ONAP Portal
111          *            session key.
112          * @param ckey
113          *            Key for the key-value pair to fetch
114          * @return JSON with shared context object; response=null if not found.
115          * @throws Exception
116          *             on bad arguments
117          */
118         @ApiOperation(value = "Gets a value for the specified context and key.", response = SharedContext.class)
119         @GetMapping(value = { "/get" }, produces = "application/json")
120         public String getContext(HttpServletRequest request, @RequestParam String context_id, @RequestParam String ckey)
121                         throws Exception {
122                 logger.debug(EELFLoggerDelegate.debugLogger, "getContext for ID " + context_id + ", key " + ckey);
123                 if (context_id == null || ckey == null)
124                         throw new Exception("Received null for context_id and/or ckey");
125                 SecureString secureContextId = new SecureString(context_id);
126                 SecureString secureCKey = new SecureString(ckey);
127
128                 if(!dataValidator.isValid(secureContextId) || !dataValidator.isValid(secureCKey)){
129                         throw new NotValidDataException("Received not valid for context_id and/or ckey");
130                 }
131
132                 SharedContext context = contextService.getSharedContext(context_id, ckey);
133                 String jsonResponse;
134                 if (context == null)
135                         jsonResponse = convertResponseToJSON(context);
136                 else
137                         jsonResponse = mapper.writeValueAsString(context);
138
139                 return jsonResponse;
140         }
141
142         /**
143          * Gets user information for the specified context (RESTful service method).
144          *
145          * @param request
146          *            HTTP servlet request
147          * @param context_id
148          *            ID that identifies the context, usually the ONAP Portal
149          *            session key.
150          * @return List of shared-context objects as JSON; should have user's first
151          *         name, last name and email address; null if none found
152          * @throws Exception
153          *             on bad arguments
154          */
155         @ApiOperation(value = "Gets user information for the specified context.", response = SharedContext.class, responseContainer = "List")
156         @GetMapping(value = { "/get_user" }, produces = "application/json")
157         public String getUserContext(HttpServletRequest request, @RequestParam String context_id) throws Exception {
158
159                 logger.debug(EELFLoggerDelegate.debugLogger, "getUserContext for ID " + context_id);
160                 if (context_id == null)
161                         throw new Exception("Received null for context_id");
162                 SecureString secureContextId = new SecureString(context_id);
163                 if (!dataValidator.isValid(secureContextId))
164                         throw new NotValidDataException("context_id is not valid");
165
166                 List<SharedContext> listSharedContext = new ArrayList<>();
167                 SharedContext firstNameContext = contextService.getSharedContext(context_id,
168                                 EPCommonSystemProperties.USER_FIRST_NAME);
169                 SharedContext lastNameContext = contextService.getSharedContext(context_id,
170                                 EPCommonSystemProperties.USER_LAST_NAME);
171                 SharedContext emailContext = contextService.getSharedContext(context_id, EPCommonSystemProperties.USER_EMAIL);
172                 SharedContext orgUserIdContext = contextService.getSharedContext(context_id,
173                                 EPCommonSystemProperties.USER_ORG_USERID);
174                 if (firstNameContext != null)
175                         listSharedContext.add(firstNameContext);
176                 if (lastNameContext != null)
177                         listSharedContext.add(lastNameContext);
178                 if (emailContext != null)
179                         listSharedContext.add(emailContext);
180                 if (orgUserIdContext != null)
181                         listSharedContext.add(orgUserIdContext);
182                 return convertResponseToJSON(listSharedContext);
183         }
184
185         /**
186          * Tests for presence of the specified key in the specified context (RESTful
187          * service method).
188          *
189          * @param request
190          *            HTTP servlet request
191          * @param context_id
192          *            ID that identifies the context, usually the ONAP Portal
193          *            session key.
194          * @param ckey
195          *            Key for the key-value pair to test
196          * @return JSON with result indicating whether the context and key were
197          *         found.
198          * @throws Exception
199          *             on bad arguments
200          */
201         @ApiOperation(value = "Tests for presence of the specified key in the specified context.", response = SharedContextJsonResponse.class)
202         @GetMapping(value = { "/check" }, produces = "application/json")
203         public String checkContext(HttpServletRequest request, @RequestParam String context_id, @RequestParam String ckey)
204                         throws Exception {
205
206                 logger.debug(EELFLoggerDelegate.debugLogger, "checkContext for " + context_id + ", key " + ckey);
207                 if (context_id == null || ckey == null)
208                         throw new Exception("Received null for contextId and/or key");
209
210                 SecureString secureContextId = new SecureString(context_id);
211                 SecureString secureCKey = new SecureString(ckey);
212
213                 if (!dataValidator.isValid(secureContextId) || !dataValidator.isValid(secureCKey))
214                         throw new NotValidDataException("Not valid data for contextId and/or key");
215
216                 String response = null;
217                 SharedContext context = contextService.getSharedContext(context_id, ckey);
218                 if (context != null)
219                         response = "exists";
220
221                 return convertResponseToJSON(response);
222         }
223
224         /**
225          * Removes the specified key in the specified context (RESTful service
226          * method).
227          *
228          * @param request
229          *            HTTP servlet request
230          * @param context_id
231          *            ID that identifies the context, usually the ONAP Portal
232          *            session key.
233          * @param ckey
234          *            Key for the key-value pair to remove
235          * @return JSON with result indicating whether the context and key were
236          *         found.
237          * @throws Exception
238          *             on bad arguments
239          */
240         @ApiOperation(value = "Removes the specified key in the specified context.", response = SharedContextJsonResponse.class)
241         @GetMapping(value = { "/remove" }, produces = "application/json")
242         public String removeContext(HttpServletRequest request, @RequestParam String context_id, @RequestParam String ckey)
243                         throws Exception {
244
245                 logger.debug(EELFLoggerDelegate.debugLogger, "removeContext for " + context_id + ", key " + ckey);
246                 if (context_id == null || ckey == null)
247                         throw new Exception("Received null for contextId and/or key");
248
249                 SecureString secureContextId = new SecureString(context_id);
250                 SecureString secureCKey = new SecureString(ckey);
251
252                 if (!dataValidator.isValid(secureContextId) || !dataValidator.isValid(secureCKey))
253                         throw new NotValidDataException("Not valid data for contextId and/or key");
254
255                 SharedContext context = contextService.getSharedContext(context_id, ckey);
256                 String response = null;
257                 if (context != null) {
258                         contextService.deleteSharedContext(context);
259                         response = "removed";
260                 }
261
262                 return convertResponseToJSON(response);
263         }
264
265         /**
266          * Clears all key-value pairs in the specified context (RESTful service
267          * method).
268          *
269          * @param request
270          *            HTTP servlet request
271          * @param context_id
272          *            ID that identifies the context, usually the ONAP Portal
273          *            session key.
274          * @return JSON with result indicating the number of key-value pairs
275          *         removed.
276          * @throws Exception
277          *             on bad arguments
278          */
279         @ApiOperation(value = "Clears all key-value pairs in the specified context.", response = SharedContextJsonResponse.class)
280         @GetMapping(value = { "/clear" }, produces = "application/json")
281         public String clearContext(HttpServletRequest request, @RequestParam String context_id) throws Exception {
282
283                 logger.debug(EELFLoggerDelegate.debugLogger, "clearContext for " + context_id);
284                 if (context_id == null)
285                         throw new Exception("clearContext: Received null for contextId");
286
287                 SecureString secureContextId = new SecureString(context_id);
288
289                 if (!dataValidator.isValid(secureContextId))
290                         throw new NotValidDataException("Not valid data for contextId");
291
292                 int count = contextService.deleteSharedContexts(context_id);
293                 return convertResponseToJSON(Integer.toString(count));
294         }
295
296         /**
297          * Sets a context value for the specified context and key (RESTful service
298          * method). Creates the context if no context with the specified ID-key pair
299          * exists, overwrites the value if it exists already.
300          *
301          * @param request
302          *            HTTP servlet request
303          * @param userJson
304          *            JSON block with these tag-value pairs:
305          *            <UL>
306          *            <LI>context_id: ID that identifies the context
307          *            <LI>ckey: Key for the key-value pair to store
308          *            <LI>cvalue: Value to store
309          *            </UL>
310          * @return JSON with result indicating whether the value was added (key not
311          *         previously known) or replaced (key previously known).
312          * @throws Exception
313          *             on bad arguments
314          */
315         @ApiOperation(value = "Sets a context value for the specified context and key. Creates the context if no context with the specified ID-key pair exists, overwrites the value if it exists already.", response = SharedContextJsonResponse.class)
316         @PostMapping(value = { "/set" }, produces = "application/json")
317         public String setContext(HttpServletRequest request, @RequestBody String userJson) throws Exception {
318                 if (userJson !=null){
319                 SecureString secureUserJson = new SecureString(userJson);
320                 if (!dataValidator.isValid(secureUserJson))
321                         throw new NotValidDataException("Not valid data for userJson");
322                 }
323
324                 @SuppressWarnings("unchecked")
325                 Map<String, Object> userData = mapper.readValue(userJson, Map.class);
326                 // Use column names as JSON tags
327                 final String contextId = (String) userData.get("context_id");
328                 final String key = (String) userData.get("ckey");
329                 final String value = (String) userData.get("cvalue");
330                 if (contextId == null || key == null)
331                         throw new Exception("setContext: received null for contextId and/or key");
332
333                 logger.debug(EELFLoggerDelegate.debugLogger, "setContext: ID " + contextId + ", key " + key + "->" + value);
334                 String response;
335                 SharedContext existing = contextService.getSharedContext(contextId, key);
336                 if (existing == null) {
337                         contextService.addSharedContext(contextId, key, value);
338                 } else {
339                         existing.setCvalue(value);
340                         contextService.saveSharedContext(existing);
341                 }
342                 response = existing == null ? "added" : "replaced";
343                 return convertResponseToJSON(response);
344         }
345
346         /**
347          * Creates a two-element JSON object tagged "response".
348          *
349          * @param responseBody
350          * @return JSON object as String
351          * @throws JsonProcessingException
352          */
353         private String convertResponseToJSON(String responseBody) throws JsonProcessingException {
354                 Map<String, String> responseMap = new HashMap<>();
355                 responseMap.put("response", responseBody);
356                 return mapper.writeValueAsString(responseMap);
357         }
358
359         /**
360          * Converts a list of SharedContext objects to a JSON array.
361          *
362          * @param contextList
363          * @return JSON array as String
364          * @throws JsonProcessingException
365          */
366         private String convertResponseToJSON(List<SharedContext> contextList) throws JsonProcessingException {
367                 return mapper.writeValueAsString(contextList);
368         }
369
370         /**
371          * Creates a JSON object with the content of the shared context; null is ok.
372          *
373          * @param context
374          * @return tag "response" with collection of context object's fields
375          * @throws JsonProcessingException
376          */
377         private String convertResponseToJSON(SharedContext context) throws JsonProcessingException {
378                 Map<String, Object> responseMap = new HashMap<>();
379                 responseMap.put("response", context);
380                 return mapper.writeValueAsString(responseMap);
381         }
382
383         /**
384          * Handles any exception thrown by a method in this controller.
385          *
386          * @param e
387          *            Exception
388          * @param response
389          *            HttpServletResponse
390          * @throws IOException
391          */
392         @ExceptionHandler(Exception.class)
393         protected void handleBadRequests(Exception e, HttpServletResponse response) throws IOException {
394                 logger.error(EELFLoggerDelegate.errorLogger, "handleBadRequest caught exception", e);
395                 response.sendError(HttpStatus.BAD_REQUEST.value(), e.getMessage());
396         }
397
398 }
399 class SharedContextJsonResponse {
400         String response;
401 }
402