2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (c) 2017 AT&T Intellectual Property
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.
19 * ============LICENSE_END=============================================
20 * ====================================================================
22 package org.onap.music.rest;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.nio.ByteBuffer;
31 import java.nio.charset.Charset;
32 import java.util.ArrayList;
34 import java.util.Map.Entry;
36 import java.util.UUID;
38 import javax.ws.rs.Consumes;
39 import javax.ws.rs.DELETE;
40 import javax.ws.rs.POST;
41 import javax.ws.rs.PUT;
42 import javax.ws.rs.Path;
43 import javax.ws.rs.Produces;
44 import javax.ws.rs.core.MediaType;
45 import javax.ws.rs.core.Response;
46 import javax.ws.rs.core.Response.ResponseBuilder;
47 import javax.ws.rs.core.Response.Status;
49 import org.codehaus.jackson.map.ObjectMapper;
50 import org.mindrot.jbcrypt.BCrypt;
51 import org.onap.music.datastore.PreparedQueryObject;
52 import org.onap.music.datastore.jsonobjects.JSONCallbackResponse;
53 import org.onap.music.datastore.jsonobjects.JSONObject;
54 import org.onap.music.datastore.jsonobjects.JsonCallback;
55 import org.onap.music.datastore.jsonobjects.JsonNotification;
56 import org.onap.music.datastore.jsonobjects.JsonNotifyClientResponse;
57 import org.onap.music.datastore.jsonobjects.JsonOnboard;
58 import org.onap.music.eelf.logging.EELFLoggerDelegate;
59 import org.onap.music.eelf.logging.format.AppMessages;
60 import org.onap.music.eelf.logging.format.ErrorSeverity;
61 import org.onap.music.eelf.logging.format.ErrorTypes;
62 //import org.onap.music.main.CacheAccess;
63 import org.onap.music.main.CachingUtil;
64 import org.onap.music.main.MusicCore;
65 import org.onap.music.main.MusicUtil;
66 import org.onap.music.main.ResultType;
67 import org.onap.music.main.ReturnType;
68 import org.onap.music.response.jsonobjects.JsonResponse;
70 import com.datastax.driver.core.DataType;
71 import com.datastax.driver.core.ResultSet;
72 import com.datastax.driver.core.Row;
73 import com.datastax.driver.core.exceptions.InvalidQueryException;
74 import com.sun.jersey.api.client.Client;
75 import com.sun.jersey.api.client.ClientResponse;
76 import com.sun.jersey.api.client.WebResource;
77 import com.sun.jersey.core.util.Base64;
79 import io.swagger.annotations.Api;
80 import io.swagger.annotations.ApiOperation;
81 import com.datastax.driver.core.TableMetadata;
83 import javax.ws.rs.core.HttpHeaders;
84 import javax.ws.rs.core.MediaType;
85 import com.datastax.driver.core.ColumnDefinitions;
86 import com.datastax.driver.core.ColumnDefinitions.Definition;
87 import com.datastax.driver.core.TableMetadata;
88 //import java.util.Base64.Encoder;
89 //import java.util.Base64.Decoder;
92 // @Path("/v{version: [0-9]+}/admin")
94 @Api(value = "Admin Api", hidden = true)
95 public class RestMusicAdminAPI {
96 private static EELFLoggerDelegate logger =
97 EELFLoggerDelegate.getLogger(RestMusicAdminAPI.class);
99 * API to onboard an application with MUSIC. This is the mandatory first step.
103 @Path("/onboardAppWithMusic")
104 @ApiOperation(value = "Onboard application", response = String.class)
105 @Consumes(MediaType.APPLICATION_JSON)
106 @Produces(MediaType.APPLICATION_JSON)
107 public Response onboardAppWithMusic(JsonOnboard jsonObj) throws Exception {
108 ResponseBuilder response =
109 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
110 Map<String, Object> resultMap = new HashMap<>();
111 String appName = jsonObj.getAppname();
112 String userId = jsonObj.getUserId();
113 String isAAF = jsonObj.getIsAAF();
114 String password = jsonObj.getPassword();
115 if (appName == null || userId == null || isAAF == null || password == null) {
116 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
117 ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
118 resultMap.put("Exception",
119 "Unauthorized: Please check the request parameters. Some of the required values appName(ns), userId, password, isAAF are missing.");
120 return Response.status(Status.UNAUTHORIZED).entity(resultMap).build();
123 PreparedQueryObject pQuery = new PreparedQueryObject();
124 pQuery.appendQueryString(
125 "select uuid from admin.keyspace_master where application_name = ? allow filtering");
126 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
127 ResultSet rs = MusicCore.get(pQuery);
128 if (!rs.all().isEmpty()) {
129 resultMap.put("Exception", "Application " + appName
130 + " has already been onboarded. Please contact admin.");
131 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
134 pQuery = new PreparedQueryObject();
135 String uuid = CachingUtil.generateUUID();
136 pQuery.appendQueryString(
137 "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
138 + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)");
139 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
140 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
141 MusicUtil.DEFAULTKEYSPACENAME));
142 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
143 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
144 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt())));
145 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
146 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
148 String returnStr = MusicCore.eventualPut(pQuery).toString();
149 if (returnStr.contains("Failure")) {
150 resultMap.put("Exception",
151 "Oops. Something wrong with onboarding process. Please retry later or contact admin.");
152 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
154 CachingUtil.updateisAAFCache(appName, isAAF);
155 resultMap.put("Success", "Your application " + appName + " has been onboarded with MUSIC.");
156 resultMap.put("Generated AID", uuid);
157 return Response.status(Status.OK).entity(resultMap).build();
163 @ApiOperation(value = "Search Onboard application", response = String.class)
164 @Consumes(MediaType.APPLICATION_JSON)
165 @Produces(MediaType.APPLICATION_JSON)
166 public Response getOnboardedInfoSearch(JsonOnboard jsonObj) throws Exception {
167 Map<String, Object> resultMap = new HashMap<>();
168 ResponseBuilder response =
169 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
170 String appName = jsonObj.getAppname();
171 String uuid = jsonObj.getAid();
172 String isAAF = jsonObj.getIsAAF();
174 if (appName == null && uuid == null && isAAF == null) {
175 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
176 ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
177 resultMap.put("Exception",
178 "Unauthorized: Please check the request parameters. Enter atleast one of the following parameters: appName(ns), aid, isAAF.");
179 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
182 PreparedQueryObject pQuery = new PreparedQueryObject();
183 String cql = "select uuid, keyspace_name from admin.keyspace_master where ";
185 cql = cql + "application_name = ? AND ";
187 cql = cql + "uuid = ? AND ";
189 cql = cql + "is_aaf = ?";
191 if (cql.endsWith("AND "))
192 cql = cql.trim().substring(0, cql.length() - 4);
193 logger.info("Query in callback is: " + cql);
194 cql = cql + " allow filtering";
195 pQuery.appendQueryString(cql);
197 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
199 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
201 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(),
202 Boolean.parseBoolean(isAAF)));
203 ResultSet rs = MusicCore.get(pQuery);
204 Iterator<Row> it = rs.iterator();
205 while (it.hasNext()) {
206 Row row = (Row) it.next();
207 resultMap.put(row.getUUID("uuid").toString(), row.getString("keyspace_name"));
209 if (resultMap.isEmpty()) {
211 resultMap.put("Exception",
212 "Please make sure Aid is correct and application is onboarded.");
213 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
215 resultMap.put("Exception",
216 "Application is not onboarded. Please make sure all the information is correct.");
217 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
220 return Response.status(Status.OK).entity(resultMap).build();
225 @Path("/onboardAppWithMusic")
226 @ApiOperation(value = "Delete Onboard application", response = String.class)
227 @Consumes(MediaType.APPLICATION_JSON)
228 @Produces(MediaType.APPLICATION_JSON)
229 public Response deleteOnboardApp(JsonOnboard jsonObj) throws Exception {
230 Map<String, Object> resultMap = new HashMap<>();
231 ResponseBuilder response =
232 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
233 String appName = jsonObj.getAppname();
234 String aid = jsonObj.getAid();
235 PreparedQueryObject pQuery = new PreparedQueryObject();
236 String consistency = MusicUtil.EVENTUAL;;
237 if (appName == null && aid == null) {
238 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
239 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
240 resultMap.put("Exception", "Please make sure either appName(ns) or Aid is present");
241 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
244 pQuery.appendQueryString(
245 "SELECT keyspace_name FROM admin.keyspace_master WHERE uuid = ?");
246 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
247 UUID.fromString(aid)));
248 Row row = MusicCore.get(pQuery).one();
250 String ks = row.getString("keyspace_name");
251 if (!ks.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
252 PreparedQueryObject queryObject = new PreparedQueryObject();
253 queryObject.appendQueryString("DROP KEYSPACE IF EXISTS " + ks + ";");
254 MusicCore.nonKeyRelatedPut(queryObject, consistency);
257 pQuery = new PreparedQueryObject();
258 pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ? IF EXISTS");
259 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
260 UUID.fromString(aid)));
261 ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
262 if (result == ResultType.SUCCESS) {
263 resultMap.put("Success", "Your application has been deleted successfully");
265 resultMap.put("Exception",
266 "Oops. Something went wrong. Please make sure Aid is correct or Application is onboarded");
267 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
268 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
269 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
272 return Response.status(Status.OK).entity(resultMap).build();
275 pQuery.appendQueryString(
276 "select uuid from admin.keyspace_master where application_name = ? allow filtering");
277 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
278 ResultSet rs = MusicCore.get(pQuery);
279 List<Row> rows = rs.all();
281 if (rows.size() == 0) {
282 resultMap.put("Exception",
283 "Application not found. Please make sure Application exists.");
284 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
285 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
286 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
287 } else if (rows.size() == 1) {
288 uuid = rows.get(0).getUUID("uuid").toString();
289 pQuery = new PreparedQueryObject();
290 pQuery.appendQueryString(
291 "SELECT keyspace_name FROM admin.keyspace_master WHERE uuid = ?");
292 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
293 UUID.fromString(uuid)));
294 Row row = MusicCore.get(pQuery).one();
295 String ks = row.getString("keyspace_name");
296 if (!ks.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
297 PreparedQueryObject queryObject = new PreparedQueryObject();
298 queryObject.appendQueryString("DROP KEYSPACE " + ks + ";");
299 MusicCore.nonKeyRelatedPut(queryObject, consistency);
302 pQuery = new PreparedQueryObject();
303 pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
304 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
305 UUID.fromString(uuid)));
306 MusicCore.eventualPut(pQuery);
307 resultMap.put("Success", "Your application " + appName + " has been deleted.");
308 return Response.status(Status.OK).entity(resultMap).build();
310 resultMap.put("Failure",
311 "More than one Aid exists for this application, so please provide Aid.");
312 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MULTIPLERECORDS,
313 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
314 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
320 @Path("/onboardAppWithMusic")
321 @ApiOperation(value = "Update Onboard application", response = String.class)
322 @Consumes(MediaType.APPLICATION_JSON)
323 @Produces(MediaType.APPLICATION_JSON)
324 public Response updateOnboardApp(JsonOnboard jsonObj) throws Exception {
325 Map<String, Object> resultMap = new HashMap<>();
326 ResponseBuilder response =
327 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
328 String aid = jsonObj.getAid();
329 String appName = jsonObj.getAppname();
330 String userId = jsonObj.getUserId();
331 String isAAF = jsonObj.getIsAAF();
332 String password = jsonObj.getPassword();
333 String consistency = "eventual";
334 PreparedQueryObject pQuery;
337 resultMap.put("Exception", "Please make sure Aid is present");
338 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
339 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
340 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
343 if (appName == null && userId == null && password == null && isAAF == null) {
344 resultMap.put("Exception",
345 "No parameters found to update. Please update atleast one parameter.");
346 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
347 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
348 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
351 if (appName != null) {
352 pQuery = new PreparedQueryObject();
353 pQuery.appendQueryString(
354 "select uuid from admin.keyspace_master where application_name = ? allow filtering");
355 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
356 ResultSet rs = MusicCore.get(pQuery);
357 if (!rs.all().isEmpty()) {
358 resultMap.put("Exception", "Application " + appName
359 + " has already been onboarded. Please contact admin.");
360 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.ALREADYEXIST,
361 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
362 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
366 pQuery = new PreparedQueryObject();
367 StringBuilder preCql = new StringBuilder("UPDATE admin.keyspace_master SET ");
369 preCql.append(" application_name = ?,");
371 preCql.append(" username = ?,");
372 if (password != null)
373 preCql.append(" password = ?,");
375 preCql.append(" is_aaf = ?,");
376 preCql.deleteCharAt(preCql.length() - 1);
377 preCql.append(" WHERE uuid = ? IF EXISTS");
378 pQuery.appendQueryString(preCql.toString());
380 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
382 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
383 if (password != null)
384 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt())));
386 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
388 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), UUID.fromString(aid)));
389 ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
391 if (result == ResultType.SUCCESS) {
392 resultMap.put("Success", "Your application has been updated successfully");
394 resultMap.put("Exception",
395 "Oops. Something went wrong. Please make sure Aid is correct and application is onboarded");
396 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
397 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
398 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
401 return Response.status(Status.OK).entity(resultMap).build();
404 Client client = Client.create();
405 ObjectMapper mapper = new ObjectMapper();
408 @Path("/callbackOps")
409 @Produces(MediaType.APPLICATION_JSON)
410 @Consumes(MediaType.APPLICATION_JSON)
411 public Response callbackOps(final JSONObject inputJsonObj) {
412 // {"keyspace":"conductor","full_table":"conductor.plans","changeValue":{"conductor.plans.status":"Who??","position":"3"},"operation":"update","table_name":"plans","primary_key":"3"}
413 Map<String, Object> resultMap = new HashMap<>();
414 new Thread(new Runnable() {
416 makeAsyncCall(inputJsonObj);
420 return Response.status(Status.OK).entity(resultMap).build();
423 private Response makeAsyncCall(JSONObject inputJsonObj) {
425 Map<String, Object> resultMap = new HashMap<>();
427 logger.info(EELFLoggerDelegate.applicationLogger, "Got notification: " + inputJsonObj.getData());
428 String dataStr = inputJsonObj.getData();
429 JSONCallbackResponse jsonResponse = mapper.readValue(dataStr, JSONCallbackResponse.class);
430 String operation = jsonResponse.getOperation();
431 Map<String, String> changeValueMap = jsonResponse.getChangeValue();
432 String primaryKey = jsonResponse.getPrimary_key();
433 String ksTableName = jsonResponse.getFull_table(); //conductor.plans
434 if(ksTableName.equals("admin.notification_master")) {
435 CachingUtil.updateCallbackNotifyList(new ArrayList<String>());
436 return Response.status(Status.OK).entity(resultMap).build();
438 List<String> inputUpdateList = jsonResponse.getUpdateList();
439 /*String field_value = changeValueMap.get("field_value");
440 if(field_value == null)
441 field_value = jsonResponse.getFull_table();*/
442 String field_value = null;
443 List<String> notifiyList = CachingUtil.getCallbackNotifyList();
444 if(notifiyList == null || notifiyList.isEmpty()) {
445 logger.info("Is cache empty? reconstructing Object from cache..");
446 constructJsonCallbackFromCache();
447 /*notifiyList = CachingUtil.getCallbackNotifyList();
448 if("update".equals(operation)) {
449 List<String> updateList = jsonResponse.getUpdateList();
450 //logger.info("update list from trigger: "+updateList);
451 for(String element : updateList) {
452 logger.info("element: "+element);
453 logger.info("notifiyList: "+notifiyList);
454 if(notifiyList.contains(element)) {
455 logger.info("Found the notifyOn property: "+element);
456 field_value = element;
461 baseRequestObj = CachingUtil.getCallBackCache(field_value);
462 logger.info("Reconstructing Object from cache is Successful.."+baseRequestObj);*/
464 notifiyList = CachingUtil.getCallbackNotifyList();
465 JsonCallback baseRequestObj = null;
467 if("update".equals(operation)) {
468 for(String element: inputUpdateList) {
469 baseRequestObj = CachingUtil.getCallBackCache(element);
470 if(baseRequestObj != null) {
471 logger.info("Found the element that was changed... "+element);
476 List<String> updateList = jsonResponse.getUpdateList();
477 //logger.info("update list from trigger: "+updateList);
478 for(String element : updateList) {
479 if(notifiyList.contains(element)) {
480 logger.info("Found the notifyOn property: "+element);
481 field_value = element;
486 field_value = jsonResponse.getFull_table();
487 baseRequestObj = CachingUtil.getCallBackCache(field_value);
490 if(baseRequestObj == null) {
491 resultMap.put("Exception",
492 "Oops. Something went wrong. Please make sure Callback properties are onboarded.");
493 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
494 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
495 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
497 logger.info("Going through list: "+operation+ " && List: "+jsonResponse.getUpdateList());
499 String key = "admin" + "." + "notification_master" + "." + baseRequestObj.getUuid();
500 String lockId = MusicCore.createLockReference(key);
501 ReturnType lockAcqResult = MusicCore.acquireLock(key, lockId);
502 if(! lockAcqResult.getResult().toString().equals("SUCCESS")) {
503 logger.error(EELFLoggerDelegate.errorLogger, "Some other node is notifying the caller..: ");
506 logger.info(operation+ ": Operation :: changeValue: "+changeValueMap);
507 if(operation.equals("update")) {
508 String notifyWhenChangeIn = baseRequestObj.getNotifyWhenChangeIn(); // conductor.plans.status
509 if(null!=field_value) {
510 if(field_value.equals(notifyWhenChangeIn)) {
511 notifyCallBackAppl(jsonResponse, baseRequestObj);
514 } else if(operation.equals("delete")) {
515 String notifyWhenDeletesIn = baseRequestObj.getNotifyWhenDeletesIn(); // conductor.plans.status
516 if(null!=field_value) {
517 if(field_value.equals(notifyWhenDeletesIn)) {
518 notifyCallBackAppl(jsonResponse, baseRequestObj);
521 } else if(operation.equals("insert")) {
522 String notifyWhenInsertsIn = baseRequestObj.getNotifyWhenInsertsIn(); // conductor.plans.status
523 if(null!=field_value) {
524 if(field_value.equals(notifyWhenInsertsIn)) {
525 notifyCallBackAppl(jsonResponse, baseRequestObj);
529 MusicCore.releaseLock(lockId, true);
530 } catch(Exception e) {
532 logger.info("Exception...");
534 logger.info(EELFLoggerDelegate.applicationLogger, "callback is completed. Notification was sent from Music...");
535 return Response.status(Status.OK).entity(resultMap).build();
538 private void notifyCallBackAppl(JSONCallbackResponse jsonResponse, JsonCallback baseRequestObj) {
539 int notifytimeout = MusicUtil.getNotifyTimeout();
540 int notifyinterval = MusicUtil.getNotifyInterval();
541 String endpoint = baseRequestObj.getApplicationNotificationEndpoint();
542 String username = baseRequestObj.getApplicationUsername();
543 String password = baseRequestObj.getApplicationPassword();
544 JsonNotification jsonNotification = constructJsonNotification(jsonResponse, baseRequestObj);
545 jsonNotification.setOperation_type(jsonResponse.getOperation());
546 logger.info(EELFLoggerDelegate.applicationLogger, "Notification Response sent is: "+jsonNotification);
547 WebResource webResource = client.resource(endpoint);
548 String authData = username+":"+password;
549 byte[] plainCredsBytes = authData.getBytes();
550 byte[] base64CredsBytes = Base64.encode(plainCredsBytes);
551 String base64Creds = new String(base64CredsBytes);
552 Map<String, String> response_body = baseRequestObj.getResponseBody();
553 ClientResponse response = null;
555 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
556 .post(ClientResponse.class, jsonNotification);
557 } catch (com.sun.jersey.api.client.ClientHandlerException chf) {
559 logger.info(EELFLoggerDelegate.applicationLogger, "Is Service down?");
560 long now= System.currentTimeMillis();
561 long end = now+notifytimeout;
563 logger.info(EELFLoggerDelegate.applicationLogger, "retrying since error in notifying callback..");
565 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
566 .post(ClientResponse.class, jsonNotification);
567 if(response.getStatus() == 200) ok = true;
568 }catch (Exception e) {
569 logger.info(EELFLoggerDelegate.applicationLogger, "Retry until "+(end-System.currentTimeMillis()));
570 if(response == null && System.currentTimeMillis() < end) ok = false;
572 try{ Thread.sleep(notifyinterval); } catch(Exception e1) {}
576 if(response == null) {
577 logger.error(EELFLoggerDelegate.errorLogger, "Can NOT notify the caller as caller failed to respond..");
580 JsonNotifyClientResponse responseStr = response.getEntity(JsonNotifyClientResponse.class);
581 logger.info(EELFLoggerDelegate.applicationLogger, "Response from Notified client: "+responseStr);
583 if(response.getStatus() != 200){
584 long now= System.currentTimeMillis();
585 long end = now+30000;
586 while(response.getStatus() != 200 && System.currentTimeMillis() < end) {
587 logger.info(EELFLoggerDelegate.applicationLogger, "retrying since error in notifying callback..");
588 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
589 .post(ClientResponse.class, jsonNotification);
591 logger.info(EELFLoggerDelegate.applicationLogger, "Exception while notifying.. "+response.getStatus());
595 private JsonNotification constructJsonNotification(JSONCallbackResponse jsonResponse, JsonCallback baseRequestObj) {
597 JsonNotification jsonNotification = new JsonNotification();
599 jsonNotification.setNotify_field(baseRequestObj.getNotifyOn());
600 jsonNotification.setEndpoint(baseRequestObj.getApplicationNotificationEndpoint());
601 jsonNotification.setUsername(baseRequestObj.getApplicationUsername());
602 jsonNotification.setPassword(baseRequestObj.getApplicationPassword());
603 String pkValue = jsonResponse.getPrimary_key();
605 String[] fullNotifyArr = baseRequestObj.getNotifyOn().split(":");
607 String[] tableArr = fullNotifyArr[0].split("\\.");
608 TableMetadata tableInfo = MusicCore.returnColumnMetadata(tableArr[0], tableArr[1]);
609 DataType primaryIdType = tableInfo.getPrimaryKey().get(0).getType();
610 String primaryId = tableInfo.getPrimaryKey().get(0).getName();
612 Map<String, String> responseBodyMap = baseRequestObj.getResponseBody();
613 for (Entry<String, String> entry : new HashSet<>(responseBodyMap.entrySet())) {
614 String trimmed = entry.getKey().trim();
615 if (!trimmed.equals(entry.getKey())) {
616 responseBodyMap.remove(entry.getKey());
617 responseBodyMap.put(trimmed, entry.getValue());
621 Set<String> keySet = responseBodyMap.keySet();
622 String cql = "select *";
623 /*for(String keys: keySet) {
624 cql = cql + keys + ",";
626 //cql = cql.substring(0, cql.length()-1);
627 cql = cql + " FROM "+fullNotifyArr[0]+" WHERE "+primaryId+" = ?";
628 logger.info("CQL in constructJsonNotification: "+cql);
629 PreparedQueryObject pQuery = new PreparedQueryObject();
630 pQuery.appendQueryString(cql);
631 pQuery.addValue(MusicUtil.convertToActualDataType(primaryIdType, pkValue));
632 Row row = MusicCore.get(pQuery).one();
633 Map<String, String> newMap = new HashMap<>();
635 ColumnDefinitions colInfo = row.getColumnDefinitions();
636 for (Definition definition : colInfo) {
637 String colName = definition.getName();
638 if(keySet.contains(colName)) {
639 DataType colType = definition.getType();
640 Object valueObj = MusicCore.getDSHandle().getColValue(row, colName, colType);
641 Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
642 logger.info(colName+" : "+valueString);
643 newMap.put(colName, valueString.toString());
644 keySet.remove(colName);
648 if(! keySet.isEmpty()) {
649 Iterator<String> iterator = keySet.iterator();
650 while (iterator.hasNext()) {
651 String element = iterator.next();
652 newMap.put(element,"COLUMN_NOT_FOUND");
657 for(String keys: keySet1) {
660 logger.info(">>>>>>>> converting <<<<<<<<<<<< "+keys + " : "+responseBodyMap.get(keys));
661 if(responseBodyMap.get(keys).equals("uuid"))
662 value = row.getUUID(keys.trim()).toString();
663 else if (responseBodyMap.get(keys).equals("text"))
664 value = row.getString(keys.trim());
665 else if (responseBodyMap.get(keys).equals("int"))
666 value = String.valueOf(row.getInt(keys.trim()));
667 else if (responseBodyMap.get(keys).equals("bigint"))
668 value = String.valueOf(row.getLong(keys.trim()));
669 } catch (Exception e) {
670 newMap.put(primaryId, pkValue);
671 logger.info("Error in constructJsonNotification: Invalid column..");
673 else if (responseBodyMap.get(keys).contains("int"))
674 value = row.getLong(keys).toString();
675 newMap.put(keys.trim(), value);
679 if("delete".equals(jsonResponse.getOperation()) || newMap.isEmpty()) {
680 newMap.put(primaryId, pkValue);
682 jsonNotification.setResponse_body(newMap);
683 } catch(Exception e) {
686 return jsonNotification;
689 private void constructJsonCallbackFromCache() throws Exception{
690 PreparedQueryObject pQuery = new PreparedQueryObject();
691 JsonCallback jsonCallback = null;
692 List<String> notifyList = new java.util.ArrayList<>();
694 "select id, endpoint_userid, endpoint_password, notify_to_endpoint, notify_insert_on,"
695 + " notify_delete_on, notify_update_on, request, notifyon from admin.notification_master allow filtering";
696 pQuery.appendQueryString(cql);
697 //pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), fullTable));
698 logger.info("Query: "+pQuery.getQuery());
700 ResultSet rs = MusicCore.get(pQuery);
701 Iterator<Row> it = rs.iterator();
702 while (it.hasNext()) {
703 Row row = (Row) it.next();
704 String endpoint = row.getString("notify_to_endpoint");
705 String username = row.getString("endpoint_userid");
706 ByteBuffer passwordBytes = row.getBytes("endpoint_password");
707 String insert = row.getString("notify_insert_on");
708 String delete = row.getString("notify_delete_on");
709 String update = row.getString("notify_update_on");
710 String request = row.getString("request");
711 String notifyon = row.getString("notifyon");
712 String uuid = row.getUUID("id").toString();
713 notifyList.add(notifyon);
714 jsonCallback = new JsonCallback();
715 jsonCallback.setApplicationNotificationEndpoint(endpoint);
717 Charset charset = Charset.forName("ISO-8859-1");
718 String decodedPwd = charset.decode(passwordBytes).toString();
719 jsonCallback.setApplicationPassword(decodedPwd);
720 jsonCallback.setApplicationUsername(username);
721 jsonCallback.setNotifyOn(notifyon);
722 jsonCallback.setNotifyWhenInsertsIn(insert);
723 jsonCallback.setNotifyWhenDeletesIn(delete);
724 jsonCallback.setNotifyWhenChangeIn(update);
725 jsonCallback.setUuid(uuid);
726 logger.info("From DB. Saved request_body: "+request);
727 request = request.substring(1, request.length()-1);
728 String[] keyValuePairs = request.split(",");
729 Map<String,String> responseBody = new HashMap<>();
731 for(String pair : keyValuePairs) {
732 String[] entry = pair.split("=");
734 if(entry.length == 2)
736 responseBody.put(entry[0], val);
738 logger.info("After parsing. Saved request_body: "+responseBody);
739 jsonCallback.setResponseBody(responseBody);
740 logger.info("Updating Cache with updateCallBackCache: "+notifyon+ " :::: "+jsonCallback);
741 CachingUtil.updateCallBackCache(notifyon, jsonCallback);
743 CachingUtil.updateCallbackNotifyList(notifyList);
747 @Path("/onboardCallback")
748 @Produces(MediaType.APPLICATION_JSON)
749 @Consumes(MediaType.APPLICATION_JSON)
750 public Response addCallback(JsonNotification jsonNotification) {
751 Map<String, Object> resultMap = new HashMap<>();
752 ResponseBuilder response =
753 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
754 String username = jsonNotification.getUsername();
755 String password = jsonNotification.getPassword();
756 String endpoint = jsonNotification.getEndpoint();
757 String notify_field = jsonNotification.getNotify_field();
758 Map<String, String> responseBody = jsonNotification.getResponse_body();
759 String triggerName = jsonNotification.getTriggerName();
760 if(triggerName == null || triggerName.length() == 0)
761 triggerName = "MusicTrigger";
763 /*JsonCallback callBackCache = CachingUtil.getCallBackCache(notify_field);
764 if(callBackCache != null) {
765 resultMap.put("Exception", "The notification property has already been onboarded.");
766 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
769 String[] allFields = notify_field.split(":");
770 String inserts = null;
771 String updates = null;
772 String deletes = null;
773 String tableName = null;
774 if(allFields.length >= 2) {
775 inserts = updates = notify_field;
776 } else if(allFields.length == 1) {
777 inserts = deletes = notify_field;;
779 tableName = allFields[0];
780 String cql = "CREATE TRIGGER IF NOT EXISTS musictrigger ON "+tableName+" Using '"+triggerName+"'";
781 PreparedQueryObject pQuery = new PreparedQueryObject();
783 String uuid = CachingUtil.generateUUID();
785 pQuery.appendQueryString(
786 "INSERT INTO admin.notification_master (id, endpoint_userid, endpoint_password, notify_to_endpoint, "
787 + "notifyon, notify_insert_on, notify_delete_on, notify_update_on, request, current_notifier) VALUES (?,?,?,?,?,?,?,?,?,?)");
788 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
789 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), username));
790 Charset charset = Charset.forName("ISO-8859-1");
791 ByteBuffer decodedPwd = charset.encode(password);
792 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.blob(), decodedPwd.array()));
793 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), endpoint));
794 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), notify_field));
795 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), inserts));
796 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), deletes));
797 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), updates));
798 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), responseBody));
799 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), MusicCore.getMyHostId()));
800 MusicCore.nonKeyRelatedPut(pQuery, MusicUtil.EVENTUAL);
801 JsonCallback jsonCallback = new JsonCallback();
802 jsonCallback.setUuid(uuid);
803 jsonCallback.setApplicationNotificationEndpoint(endpoint);
804 jsonCallback.setApplicationPassword(password);
805 jsonCallback.setApplicationUsername(username);
806 jsonCallback.setNotifyOn(notify_field);
807 jsonCallback.setNotifyWhenChangeIn(updates);
808 jsonCallback.setNotifyWhenDeletesIn(deletes);
809 jsonCallback.setNotifyWhenInsertsIn(inserts);
810 jsonCallback.setResponseBody(responseBody);
811 CachingUtil.updateCallBackCache(notify_field, jsonCallback);
812 logger.info("Cache updated ");
813 pQuery = new PreparedQueryObject();
814 pQuery.appendQueryString(cql);
815 ResultType nonKeyRelatedPut = MusicCore.nonKeyRelatedPut(pQuery, MusicUtil.EVENTUAL);
816 logger.info(EELFLoggerDelegate.applicationLogger, "Created trigger");
817 //callBackCache.put(jsonCallback.getApplicationName(), jsonMap);
818 } catch (InvalidQueryException e) {
819 logger.error(EELFLoggerDelegate.errorLogger,"Exception callback_api table not configured."+e.getMessage());
820 resultMap.put("Exception", "Please make sure admin.notification_master table is configured.");
821 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
822 } catch(Exception e) {
824 resultMap.put("Exception", "Exception Occured.");
825 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
827 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Callback api successfully registered").toMap()).build();
830 /*public String encodePwd(String password) {
831 return Base64.getEncoder().encodeToString(password.getBytes());
834 public String decodePwd(String password) {
835 byte[] bytes = Base64.getDecoder().decode(password);
836 return new String(bytes);