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