2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ===================================================================
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
26 * https://creativecommons.org/licenses/by/4.0/
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.
34 * ============LICENSE_END============================================
38 package org.onap.portalapp.portal.controller;
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.List;
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletResponse;
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.RequestMethod;
67 import org.springframework.web.bind.annotation.RequestParam;
68 import org.springframework.web.bind.annotation.RestController;
70 import com.fasterxml.jackson.core.JsonProcessingException;
71 import com.fasterxml.jackson.databind.ObjectMapper;
73 import io.swagger.annotations.ApiOperation;
76 * The shared-context feature allows onboarded applications to share data among
77 * themselves easily for a given session. It basically implements a Java map:
78 * put or get a key-value pair within a map identified by a session ID.
80 * This REST endpoint listens on the Portal app server and answers requests made
81 * by back-end application servers. Reads and writes values to the database
82 * using a Hibernate service to ensure all servers in a high-availability
83 * cluster see the same data.
87 @RequestMapping(PortalConstants.REST_AUX_API + "/context")
88 @EnableAspectJAutoProxy
90 public class SharedContextRestController extends EPRestrictedRESTfulBaseController {
91 private static final DataValidator dataValidator = new DataValidator();
92 private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SharedContextRestController.class);
93 private static final ObjectMapper mapper = new ObjectMapper();
95 private SharedContextService contextService;
98 public SharedContextRestController(SharedContextService contextService) {
99 this.contextService = contextService;
103 * Gets a value for the specified context and key (RESTful service method).
106 * HTTP servlet request
108 * ID that identifies the context, usually the ONAP Portal
111 * Key for the key-value pair to fetch
112 * @return JSON with shared context object; response=null if not found.
116 @ApiOperation(value = "Gets a value for the specified context and key.", response = SharedContext.class)
117 @RequestMapping(value = { "/get" }, method = RequestMethod.GET, produces = "application/json")
118 public String getContext(HttpServletRequest request, @RequestParam String context_id, @RequestParam String ckey)
120 logger.debug(EELFLoggerDelegate.debugLogger, "getContext for ID " + context_id + ", key " + ckey);
121 if (context_id == null || ckey == null)
122 throw new Exception("Received null for context_id and/or ckey");
123 SecureString secureContextId = new SecureString(context_id);
124 SecureString secureCKey = new SecureString(ckey);
126 if(!dataValidator.isValid(secureContextId) || !dataValidator.isValid(secureCKey)){
127 throw new NotValidDataException("Received not valid for context_id and/or ckey");
130 SharedContext context = contextService.getSharedContext(context_id, ckey);
133 jsonResponse = convertResponseToJSON(context);
135 jsonResponse = mapper.writeValueAsString(context);
141 * Gets user information for the specified context (RESTful service method).
144 * HTTP servlet request
146 * ID that identifies the context, usually the ONAP Portal
148 * @return List of shared-context objects as JSON; should have user's first
149 * name, last name and email address; null if none found
153 @ApiOperation(value = "Gets user information for the specified context.", response = SharedContext.class, responseContainer = "List")
154 @RequestMapping(value = { "/get_user" }, method = RequestMethod.GET, produces = "application/json")
155 public String getUserContext(HttpServletRequest request, @RequestParam String context_id) throws Exception {
157 logger.debug(EELFLoggerDelegate.debugLogger, "getUserContext for ID " + context_id);
158 if (context_id == null)
159 throw new Exception("Received null for context_id");
160 SecureString secureContextId = new SecureString(context_id);
161 if (!dataValidator.isValid(secureContextId))
162 throw new NotValidDataException("context_id is not valid");
164 List<SharedContext> listSharedContext = new ArrayList<>();
165 SharedContext firstNameContext = contextService.getSharedContext(context_id,
166 EPCommonSystemProperties.USER_FIRST_NAME);
167 SharedContext lastNameContext = contextService.getSharedContext(context_id,
168 EPCommonSystemProperties.USER_LAST_NAME);
169 SharedContext emailContext = contextService.getSharedContext(context_id, EPCommonSystemProperties.USER_EMAIL);
170 SharedContext orgUserIdContext = contextService.getSharedContext(context_id,
171 EPCommonSystemProperties.USER_ORG_USERID);
172 if (firstNameContext != null)
173 listSharedContext.add(firstNameContext);
174 if (lastNameContext != null)
175 listSharedContext.add(lastNameContext);
176 if (emailContext != null)
177 listSharedContext.add(emailContext);
178 if (orgUserIdContext != null)
179 listSharedContext.add(orgUserIdContext);
180 return convertResponseToJSON(listSharedContext);
184 * Tests for presence of the specified key in the specified context (RESTful
188 * HTTP servlet request
190 * ID that identifies the context, usually the ONAP Portal
193 * Key for the key-value pair to test
194 * @return JSON with result indicating whether the context and key were
199 @ApiOperation(value = "Tests for presence of the specified key in the specified context.", response = SharedContextJsonResponse.class)
200 @RequestMapping(value = { "/check" }, method = RequestMethod.GET, produces = "application/json")
201 public String checkContext(HttpServletRequest request, @RequestParam String context_id, @RequestParam String ckey)
204 logger.debug(EELFLoggerDelegate.debugLogger, "checkContext for " + context_id + ", key " + ckey);
205 if (context_id == null || ckey == null)
206 throw new Exception("Received null for contextId and/or key");
208 SecureString secureContextId = new SecureString(context_id);
209 SecureString secureCKey = new SecureString(ckey);
211 if (!dataValidator.isValid(secureContextId) || !dataValidator.isValid(secureCKey))
212 throw new NotValidDataException("Not valid data for contextId and/or key");
214 String response = null;
215 SharedContext context = contextService.getSharedContext(context_id, ckey);
219 return convertResponseToJSON(response);
223 * Removes the specified key in the specified context (RESTful service
227 * HTTP servlet request
229 * ID that identifies the context, usually the ONAP Portal
232 * Key for the key-value pair to remove
233 * @return JSON with result indicating whether the context and key were
238 @ApiOperation(value = "Removes the specified key in the specified context.", response = SharedContextJsonResponse.class)
239 @RequestMapping(value = { "/remove" }, method = RequestMethod.GET, produces = "application/json")
240 public String removeContext(HttpServletRequest request, @RequestParam String context_id, @RequestParam String ckey)
243 logger.debug(EELFLoggerDelegate.debugLogger, "removeContext for " + context_id + ", key " + ckey);
244 if (context_id == null || ckey == null)
245 throw new Exception("Received null for contextId and/or key");
247 SecureString secureContextId = new SecureString(context_id);
248 SecureString secureCKey = new SecureString(ckey);
250 if (!dataValidator.isValid(secureContextId) || !dataValidator.isValid(secureCKey))
251 throw new NotValidDataException("Not valid data for contextId and/or key");
253 SharedContext context = contextService.getSharedContext(context_id, ckey);
254 String response = null;
255 if (context != null) {
256 contextService.deleteSharedContext(context);
257 response = "removed";
260 return convertResponseToJSON(response);
264 * Clears all key-value pairs in the specified context (RESTful service
268 * HTTP servlet request
270 * ID that identifies the context, usually the ONAP Portal
272 * @return JSON with result indicating the number of key-value pairs
277 @ApiOperation(value = "Clears all key-value pairs in the specified context.", response = SharedContextJsonResponse.class)
278 @RequestMapping(value = { "/clear" }, method = RequestMethod.GET, produces = "application/json")
279 public String clearContext(HttpServletRequest request, @RequestParam String context_id) throws Exception {
281 logger.debug(EELFLoggerDelegate.debugLogger, "clearContext for " + context_id);
282 if (context_id == null)
283 throw new Exception("clearContext: Received null for contextId");
285 SecureString secureContextId = new SecureString(context_id);
287 if (!dataValidator.isValid(secureContextId))
288 throw new NotValidDataException("Not valid data for contextId");
290 int count = contextService.deleteSharedContexts(context_id);
291 return convertResponseToJSON(Integer.toString(count));
295 * Sets a context value for the specified context and key (RESTful service
296 * method). Creates the context if no context with the specified ID-key pair
297 * exists, overwrites the value if it exists already.
300 * HTTP servlet request
302 * JSON block with these tag-value pairs:
304 * <LI>context_id: ID that identifies the context
305 * <LI>ckey: Key for the key-value pair to store
306 * <LI>cvalue: Value to store
308 * @return JSON with result indicating whether the value was added (key not
309 * previously known) or replaced (key previously known).
313 @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)
314 @RequestMapping(value = { "/set" }, method = RequestMethod.POST, produces = "application/json")
315 public String setContext(HttpServletRequest request, @RequestBody String userJson) throws Exception {
316 if (userJson !=null){
317 SecureString secureUserJson = new SecureString(userJson);
318 if (!dataValidator.isValid(secureUserJson))
319 throw new NotValidDataException("Not valid data for userJson");
322 @SuppressWarnings("unchecked")
323 Map<String, Object> userData = mapper.readValue(userJson, Map.class);
324 // Use column names as JSON tags
325 final String contextId = (String) userData.get("context_id");
326 final String key = (String) userData.get("ckey");
327 final String value = (String) userData.get("cvalue");
328 if (contextId == null || key == null)
329 throw new Exception("setContext: received null for contextId and/or key");
331 logger.debug(EELFLoggerDelegate.debugLogger, "setContext: ID " + contextId + ", key " + key + "->" + value);
333 SharedContext existing = contextService.getSharedContext(contextId, key);
334 if (existing == null) {
335 contextService.addSharedContext(contextId, key, value);
337 existing.setCvalue(value);
338 contextService.saveSharedContext(existing);
340 response = existing == null ? "added" : "replaced";
341 return convertResponseToJSON(response);
345 * Creates a two-element JSON object tagged "response".
347 * @param responseBody
348 * @return JSON object as String
349 * @throws JsonProcessingException
351 private String convertResponseToJSON(String responseBody) throws JsonProcessingException {
352 Map<String, String> responseMap = new HashMap<>();
353 responseMap.put("response", responseBody);
354 return mapper.writeValueAsString(responseMap);
358 * Converts a list of SharedContext objects to a JSON array.
361 * @return JSON array as String
362 * @throws JsonProcessingException
364 private String convertResponseToJSON(List<SharedContext> contextList) throws JsonProcessingException {
365 return mapper.writeValueAsString(contextList);
369 * Creates a JSON object with the content of the shared context; null is ok.
372 * @return tag "response" with collection of context object's fields
373 * @throws JsonProcessingException
375 private String convertResponseToJSON(SharedContext context) throws JsonProcessingException {
376 Map<String, Object> responseMap = new HashMap<>();
377 responseMap.put("response", context);
378 return mapper.writeValueAsString(responseMap);
382 * Handles any exception thrown by a method in this controller.
387 * HttpServletResponse
388 * @throws IOException
390 @ExceptionHandler(Exception.class)
391 protected void handleBadRequests(Exception e, HttpServletResponse response) throws IOException {
392 logger.error(EELFLoggerDelegate.errorLogger, "handleBadRequest caught exception", e);
393 response.sendError(HttpStatus.BAD_REQUEST.value(), e.getMessage());
397 class SharedContextJsonResponse {