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.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.nio.ByteBuffer;
30 import java.nio.charset.Charset;
31 import java.util.ArrayList;
33 import java.util.Map.Entry;
35 import java.util.UUID;
37 import javax.ws.rs.Consumes;
38 import javax.ws.rs.DELETE;
39 import javax.ws.rs.POST;
40 import javax.ws.rs.PUT;
41 import javax.ws.rs.Path;
42 import javax.ws.rs.Produces;
43 import javax.ws.rs.core.MediaType;
44 import javax.ws.rs.core.Response;
45 import javax.ws.rs.core.Response.ResponseBuilder;
46 import javax.ws.rs.core.Response.Status;
48 import org.codehaus.jackson.map.ObjectMapper;
49 import org.mindrot.jbcrypt.BCrypt;
50 import org.onap.music.datastore.PreparedQueryObject;
51 import org.onap.music.datastore.jsonobjects.JSONCallbackResponse;
52 import org.onap.music.datastore.jsonobjects.JSONObject;
53 import org.onap.music.datastore.jsonobjects.JsonCallback;
54 import org.onap.music.datastore.jsonobjects.JsonNotification;
55 import org.onap.music.datastore.jsonobjects.JsonNotifyClientResponse;
56 import org.onap.music.datastore.jsonobjects.JsonOnboard;
57 import org.onap.music.eelf.logging.EELFLoggerDelegate;
58 import org.onap.music.eelf.logging.format.AppMessages;
59 import org.onap.music.eelf.logging.format.ErrorSeverity;
60 import org.onap.music.eelf.logging.format.ErrorTypes;
61 //import org.onap.music.main.CacheAccess;
62 import org.onap.music.main.CachingUtil;
63 import org.onap.music.main.MusicCore;
64 import org.onap.music.main.MusicUtil;
65 import org.onap.music.main.ResultType;
66 import org.onap.music.main.ReturnType;
67 import org.onap.music.response.jsonobjects.JsonResponse;
69 import com.datastax.driver.core.DataType;
70 import com.datastax.driver.core.ResultSet;
71 import com.datastax.driver.core.Row;
72 import com.datastax.driver.core.exceptions.InvalidQueryException;
73 import com.sun.jersey.api.client.Client;
74 import com.sun.jersey.api.client.ClientResponse;
75 import com.sun.jersey.api.client.WebResource;
76 import com.sun.jersey.core.util.Base64;
78 import io.swagger.annotations.Api;
79 import io.swagger.annotations.ApiOperation;
80 import com.datastax.driver.core.TableMetadata;
82 import javax.ws.rs.core.HttpHeaders;
83 import javax.ws.rs.core.MediaType;
84 import com.datastax.driver.core.ColumnDefinitions;
85 import com.datastax.driver.core.ColumnDefinitions.Definition;
86 import com.datastax.driver.core.TableMetadata;
87 //import java.util.Base64.Encoder;
88 //import java.util.Base64.Decoder;
91 // @Path("/v{version: [0-9]+}/admin")
93 @Api(value = "Admin Api", hidden = true)
94 public class RestMusicAdminAPI {
95 private static EELFLoggerDelegate logger =
96 EELFLoggerDelegate.getLogger(RestMusicAdminAPI.class);
98 * API to onboard an application with MUSIC. This is the mandatory first step.
102 @Path("/onboardAppWithMusic")
103 @ApiOperation(value = "Onboard application", response = String.class)
104 @Consumes(MediaType.APPLICATION_JSON)
105 @Produces(MediaType.APPLICATION_JSON)
106 public Response onboardAppWithMusic(JsonOnboard jsonObj) throws Exception {
107 ResponseBuilder response =
108 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
109 Map<String, Object> resultMap = new HashMap<>();
110 String appName = jsonObj.getAppname();
111 String userId = jsonObj.getUserId();
112 String isAAF = jsonObj.getIsAAF();
113 String password = jsonObj.getPassword();
114 if (appName == null || userId == null || isAAF == null || password == null) {
115 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
116 ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
117 resultMap.put("Exception",
118 "Unauthorized: Please check the request parameters. Some of the required values appName(ns), userId, password, isAAF are missing.");
119 return Response.status(Status.UNAUTHORIZED).entity(resultMap).build();
122 PreparedQueryObject pQuery = new PreparedQueryObject();
123 pQuery.appendQueryString(
124 "select uuid from admin.keyspace_master where application_name = ? allow filtering");
125 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
126 ResultSet rs = MusicCore.get(pQuery);
127 if (!rs.all().isEmpty()) {
128 resultMap.put("Exception", "Application " + appName
129 + " has already been onboarded. Please contact admin.");
130 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
133 pQuery = new PreparedQueryObject();
134 String uuid = CachingUtil.generateUUID();
135 pQuery.appendQueryString(
136 "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
137 + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)");
138 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
139 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
140 MusicUtil.DEFAULTKEYSPACENAME));
141 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
142 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
143 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt())));
144 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
145 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
147 String returnStr = MusicCore.eventualPut(pQuery).toString();
148 if (returnStr.contains("Failure")) {
149 resultMap.put("Exception",
150 "Oops. Something wrong with onboarding process. Please retry later or contact admin.");
151 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
153 CachingUtil.updateisAAFCache(appName, isAAF);
154 resultMap.put("Success", "Your application " + appName + " has been onboarded with MUSIC.");
155 resultMap.put("Generated AID", uuid);
156 return Response.status(Status.OK).entity(resultMap).build();
162 @ApiOperation(value = "Search Onboard application", response = String.class)
163 @Consumes(MediaType.APPLICATION_JSON)
164 @Produces(MediaType.APPLICATION_JSON)
165 public Response getOnboardedInfoSearch(JsonOnboard jsonObj) throws Exception {
166 Map<String, Object> resultMap = new HashMap<>();
167 ResponseBuilder response =
168 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
169 String appName = jsonObj.getAppname();
170 String uuid = jsonObj.getAid();
171 String isAAF = jsonObj.getIsAAF();
173 if (appName == null && uuid == null && isAAF == null) {
174 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
175 ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
176 resultMap.put("Exception",
177 "Unauthorized: Please check the request parameters. Enter atleast one of the following parameters: appName(ns), aid, isAAF.");
178 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
181 PreparedQueryObject pQuery = new PreparedQueryObject();
182 String cql = "select uuid, keyspace_name from admin.keyspace_master where ";
184 cql = cql + "application_name = ? AND ";
186 cql = cql + "uuid = ? AND ";
188 cql = cql + "is_aaf = ?";
190 if (cql.endsWith("AND "))
191 cql = cql.trim().substring(0, cql.length() - 4);
192 logger.info("Query in callback is: " + cql);
193 cql = cql + " allow filtering";
194 pQuery.appendQueryString(cql);
196 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
198 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
200 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(),
201 Boolean.parseBoolean(isAAF)));
202 ResultSet rs = MusicCore.get(pQuery);
203 Iterator<Row> it = rs.iterator();
204 while (it.hasNext()) {
205 Row row = (Row) it.next();
206 resultMap.put(row.getUUID("uuid").toString(), row.getString("keyspace_name"));
208 if (resultMap.isEmpty()) {
210 resultMap.put("Exception",
211 "Please make sure Aid is correct and application is onboarded.");
212 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
214 resultMap.put("Exception",
215 "Application is not onboarded. Please make sure all the information is correct.");
216 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
219 return Response.status(Status.OK).entity(resultMap).build();
224 @Path("/onboardAppWithMusic")
225 @ApiOperation(value = "Delete Onboard application", response = String.class)
226 @Consumes(MediaType.APPLICATION_JSON)
227 @Produces(MediaType.APPLICATION_JSON)
228 public Response deleteOnboardApp(JsonOnboard jsonObj) throws Exception {
229 Map<String, Object> resultMap = new HashMap<>();
230 ResponseBuilder response =
231 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
232 String appName = jsonObj.getAppname();
233 String aid = jsonObj.getAid();
234 PreparedQueryObject pQuery = new PreparedQueryObject();
235 String consistency = MusicUtil.EVENTUAL;;
236 if (appName == null && aid == null) {
237 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
238 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
239 resultMap.put("Exception", "Please make sure either appName(ns) or Aid is present");
240 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
243 pQuery.appendQueryString(
244 "SELECT keyspace_name FROM admin.keyspace_master WHERE uuid = ?");
245 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
246 UUID.fromString(aid)));
247 Row row = MusicCore.get(pQuery).one();
249 String ks = row.getString("keyspace_name");
250 if (!ks.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
251 PreparedQueryObject queryObject = new PreparedQueryObject();
252 queryObject.appendQueryString("DROP KEYSPACE IF EXISTS " + ks + ";");
253 MusicCore.nonKeyRelatedPut(queryObject, consistency);
256 pQuery = new PreparedQueryObject();
257 pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ? IF EXISTS");
258 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
259 UUID.fromString(aid)));
260 ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
261 if (result == ResultType.SUCCESS) {
262 resultMap.put("Success", "Your application has been deleted successfully");
264 resultMap.put("Exception",
265 "Oops. Something went wrong. Please make sure Aid is correct or Application is onboarded");
266 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
267 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
268 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
271 return Response.status(Status.OK).entity(resultMap).build();
274 pQuery.appendQueryString(
275 "select uuid from admin.keyspace_master where application_name = ? allow filtering");
276 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
277 ResultSet rs = MusicCore.get(pQuery);
278 List<Row> rows = rs.all();
280 if (rows.size() == 0) {
281 resultMap.put("Exception",
282 "Application not found. Please make sure Application exists.");
283 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
284 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
285 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
286 } else if (rows.size() == 1) {
287 uuid = rows.get(0).getUUID("uuid").toString();
288 pQuery = new PreparedQueryObject();
289 pQuery.appendQueryString(
290 "SELECT keyspace_name FROM admin.keyspace_master WHERE uuid = ?");
291 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
292 UUID.fromString(uuid)));
293 Row row = MusicCore.get(pQuery).one();
294 String ks = row.getString("keyspace_name");
295 if (!ks.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
296 PreparedQueryObject queryObject = new PreparedQueryObject();
297 queryObject.appendQueryString("DROP KEYSPACE " + ks + ";");
298 MusicCore.nonKeyRelatedPut(queryObject, consistency);
301 pQuery = new PreparedQueryObject();
302 pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
303 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
304 UUID.fromString(uuid)));
305 MusicCore.eventualPut(pQuery);
306 resultMap.put("Success", "Your application " + appName + " has been deleted.");
307 return Response.status(Status.OK).entity(resultMap).build();
309 resultMap.put("Failure",
310 "More than one Aid exists for this application, so please provide Aid.");
311 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MULTIPLERECORDS,
312 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
313 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
319 @Path("/onboardAppWithMusic")
320 @ApiOperation(value = "Update Onboard application", response = String.class)
321 @Consumes(MediaType.APPLICATION_JSON)
322 @Produces(MediaType.APPLICATION_JSON)
323 public Response updateOnboardApp(JsonOnboard jsonObj) throws Exception {
324 Map<String, Object> resultMap = new HashMap<>();
325 ResponseBuilder response =
326 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
327 String aid = jsonObj.getAid();
328 String appName = jsonObj.getAppname();
329 String userId = jsonObj.getUserId();
330 String isAAF = jsonObj.getIsAAF();
331 String password = jsonObj.getPassword();
332 String consistency = "eventual";
333 PreparedQueryObject pQuery;
336 resultMap.put("Exception", "Please make sure Aid is present");
337 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
338 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
339 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
342 if (appName == null && userId == null && password == null && isAAF == null) {
343 resultMap.put("Exception",
344 "No parameters found to update. Please update atleast one parameter.");
345 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
346 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
347 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
350 if (appName != null) {
351 pQuery = new PreparedQueryObject();
352 pQuery.appendQueryString(
353 "select uuid from admin.keyspace_master where application_name = ? allow filtering");
354 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
355 ResultSet rs = MusicCore.get(pQuery);
356 if (!rs.all().isEmpty()) {
357 resultMap.put("Exception", "Application " + appName
358 + " has already been onboarded. Please contact admin.");
359 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.ALREADYEXIST,
360 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
361 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
365 pQuery = new PreparedQueryObject();
366 StringBuilder preCql = new StringBuilder("UPDATE admin.keyspace_master SET ");
368 preCql.append(" application_name = ?,");
370 preCql.append(" username = ?,");
371 if (password != null)
372 preCql.append(" password = ?,");
374 preCql.append(" is_aaf = ?,");
375 preCql.deleteCharAt(preCql.length() - 1);
376 preCql.append(" WHERE uuid = ? IF EXISTS");
377 pQuery.appendQueryString(preCql.toString());
379 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
381 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
382 if (password != null)
383 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt())));
385 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
387 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), UUID.fromString(aid)));
388 ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
390 if (result == ResultType.SUCCESS) {
391 resultMap.put("Success", "Your application has been updated successfully");
393 resultMap.put("Exception",
394 "Oops. Something went wrong. Please make sure Aid is correct and application is onboarded");
395 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
396 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
397 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
400 return Response.status(Status.OK).entity(resultMap).build();
403 Client client = Client.create();
404 ObjectMapper mapper = new ObjectMapper();
407 @Path("/callbackOps")
408 @Produces(MediaType.APPLICATION_JSON)
409 @Consumes(MediaType.APPLICATION_JSON)
410 public Response callbackOps(final JSONObject inputJsonObj) {
411 // {"keyspace":"conductor","full_table":"conductor.plans","changeValue":{"conductor.plans.status":"Who??","position":"3"},"operation":"update","table_name":"plans","primary_key":"3"}
412 Map<String, Object> resultMap = new HashMap<>();
413 new Thread(new Runnable() {
415 makeAsyncCall(inputJsonObj);
419 return Response.status(Status.OK).entity(resultMap).build();
422 private Response makeAsyncCall(JSONObject inputJsonObj) {
424 Map<String, Object> resultMap = new HashMap<>();
426 logger.info(EELFLoggerDelegate.applicationLogger, "Got notification: " + inputJsonObj.getData());
427 String dataStr = inputJsonObj.getData();
428 JSONCallbackResponse jsonResponse = mapper.readValue(dataStr, JSONCallbackResponse.class);
429 String operation = jsonResponse.getOperation();
430 Map<String, String> changeValueMap = jsonResponse.getChangeValue();
431 String primaryKey = jsonResponse.getPrimary_key();
432 String ksTableName = jsonResponse.getFull_table(); //conductor.plans
433 if(ksTableName.equals("admin.notification_master")) {
434 CachingUtil.updateCallbackNotifyList(new ArrayList<String>());
435 return Response.status(Status.OK).entity(resultMap).build();
437 List<String> inputUpdateList = jsonResponse.getUpdateList();
438 /*String field_value = changeValueMap.get("field_value");
439 if(field_value == null)
440 field_value = jsonResponse.getFull_table();*/
441 String field_value = null;
442 List<String> notifiyList = CachingUtil.getCallbackNotifyList();
443 if(notifiyList == null || notifiyList.isEmpty()) {
444 logger.info("Is cache empty? reconstructing Object from cache..");
445 constructJsonCallbackFromCache();
446 /*notifiyList = CachingUtil.getCallbackNotifyList();
447 if("update".equals(operation)) {
448 List<String> updateList = jsonResponse.getUpdateList();
449 //logger.info("update list from trigger: "+updateList);
450 for(String element : updateList) {
451 logger.info("element: "+element);
452 logger.info("notifiyList: "+notifiyList);
453 if(notifiyList.contains(element)) {
454 logger.info("Found the notifyOn property: "+element);
455 field_value = element;
460 baseRequestObj = CachingUtil.getCallBackCache(field_value);
461 logger.info("Reconstructing Object from cache is Successful.."+baseRequestObj);*/
463 notifiyList = CachingUtil.getCallbackNotifyList();
464 JsonCallback baseRequestObj = null;
466 if("update".equals(operation)) {
467 for(String element: inputUpdateList) {
468 baseRequestObj = CachingUtil.getCallBackCache(element);
469 if(baseRequestObj != null) {
470 logger.info("Found the element that was changed... "+element);
475 List<String> updateList = jsonResponse.getUpdateList();
476 //logger.info("update list from trigger: "+updateList);
477 for(String element : updateList) {
478 if(notifiyList.contains(element)) {
479 logger.info("Found the notifyOn property: "+element);
480 field_value = element;
484 if(baseRequestObj == null || field_value == null) {
485 for(String element: inputUpdateList) {
486 String[] elementArr = element.split(":");
487 String newElement = null;
488 if(elementArr.length >= 2) {
489 newElement = elementArr[0]+":"+elementArr[1];
491 baseRequestObj = CachingUtil.getCallBackCache(newElement);
492 if(baseRequestObj != null) {
493 logger.info("Found the element that was changed... "+newElement);
497 for(String element : updateList) {
498 String[] elementArr = element.split(":");
499 String newElement = null;
500 if(elementArr.length >= 2) {
501 newElement = elementArr[0]+":"+elementArr[1];
503 if(notifiyList.contains(newElement)) {
504 logger.info("Found the notifyOn property: "+newElement);
505 field_value = newElement;
511 field_value = jsonResponse.getFull_table();
512 baseRequestObj = CachingUtil.getCallBackCache(field_value);
515 if(baseRequestObj == null) {
516 resultMap.put("Exception",
517 "Oops. Something went wrong. Please make sure Callback properties are onboarded.");
518 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
519 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
520 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
522 logger.info("Going through list: "+operation+ " && List: "+jsonResponse.getUpdateList());
524 String key = "admin" + "." + "notification_master" + "." + baseRequestObj.getUuid();
525 String lockId = MusicCore.createLockReference(key);
526 ReturnType lockAcqResult = MusicCore.acquireLock(key, lockId);
527 if(! lockAcqResult.getResult().toString().equals("SUCCESS")) {
528 logger.error(EELFLoggerDelegate.errorLogger, "Some other node is notifying the caller..: ");
531 logger.info(operation+ ": Operation :: changeValue: "+changeValueMap);
532 if(operation.equals("update")) {
533 String notifyWhenChangeIn = baseRequestObj.getNotifyWhenChangeIn(); // conductor.plans.status
534 if(null!=field_value) {
535 if(field_value.equals(notifyWhenChangeIn)) {
536 notifyCallBackAppl(jsonResponse, baseRequestObj);
539 } else if(operation.equals("delete")) {
540 String notifyWhenDeletesIn = baseRequestObj.getNotifyWhenDeletesIn(); // conductor.plans.status
541 if(null!=field_value) {
542 if(field_value.equals(notifyWhenDeletesIn)) {
543 notifyCallBackAppl(jsonResponse, baseRequestObj);
546 } else if(operation.equals("insert")) {
547 String notifyWhenInsertsIn = baseRequestObj.getNotifyWhenInsertsIn(); // conductor.plans.status
548 if(null!=field_value) {
549 if(field_value.equals(notifyWhenInsertsIn)) {
550 notifyCallBackAppl(jsonResponse, baseRequestObj);
554 MusicCore.releaseLock(lockId, true);
555 } catch(Exception e) {
557 logger.info("Exception...");
559 logger.info(EELFLoggerDelegate.applicationLogger, "callback is completed. Notification was sent from Music...");
560 return Response.status(Status.OK).entity(resultMap).build();
563 private void notifyCallBackAppl(JSONCallbackResponse jsonResponse, JsonCallback baseRequestObj) {
564 int notifytimeout = MusicUtil.getNotifyTimeout();
565 int notifyinterval = MusicUtil.getNotifyInterval();
566 String endpoint = baseRequestObj.getApplicationNotificationEndpoint();
567 String username = baseRequestObj.getApplicationUsername();
568 String password = baseRequestObj.getApplicationPassword();
569 JsonNotification jsonNotification = constructJsonNotification(jsonResponse, baseRequestObj);
570 jsonNotification.setOperation_type(jsonResponse.getOperation());
571 logger.info(EELFLoggerDelegate.applicationLogger, "Notification Response sent is: "+jsonNotification);
572 WebResource webResource = client.resource(endpoint);
573 String authData = username+":"+password;
574 byte[] plainCredsBytes = authData.getBytes();
575 byte[] base64CredsBytes = Base64.encode(plainCredsBytes);
576 String base64Creds = new String(base64CredsBytes);
577 Map<String, String> response_body = baseRequestObj.getResponseBody();
578 ClientResponse response = null;
580 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
581 .post(ClientResponse.class, jsonNotification);
582 } catch (com.sun.jersey.api.client.ClientHandlerException chf) {
584 logger.info(EELFLoggerDelegate.applicationLogger, "Is Service down?");
585 long now= System.currentTimeMillis();
586 long end = now+notifytimeout;
588 logger.info(EELFLoggerDelegate.applicationLogger, "retrying since error in notifying callback..");
590 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
591 .post(ClientResponse.class, jsonNotification);
592 if(response.getStatus() == 200) ok = true;
593 }catch (Exception e) {
594 logger.info(EELFLoggerDelegate.applicationLogger, "Retry until "+(end-System.currentTimeMillis()));
595 if(response == null && System.currentTimeMillis() < end) ok = false;
597 try{ Thread.sleep(notifyinterval); } catch(Exception e1) {}
601 if(response == null) {
602 logger.error(EELFLoggerDelegate.errorLogger, "Can NOT notify the caller as caller failed to respond..");
605 JsonNotifyClientResponse responseStr = response.getEntity(JsonNotifyClientResponse.class);
606 logger.info(EELFLoggerDelegate.applicationLogger, "Response from Notified client: "+responseStr);
608 if(response.getStatus() != 200){
609 long now= System.currentTimeMillis();
610 long end = now+30000;
611 while(response.getStatus() != 200 && System.currentTimeMillis() < end) {
612 logger.info(EELFLoggerDelegate.applicationLogger, "retrying since error in notifying callback..");
613 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
614 .post(ClientResponse.class, jsonNotification);
616 logger.info(EELFLoggerDelegate.applicationLogger, "Exception while notifying.. "+response.getStatus());
620 private JsonNotification constructJsonNotification(JSONCallbackResponse jsonResponse, JsonCallback baseRequestObj) {
622 JsonNotification jsonNotification = new JsonNotification();
624 jsonNotification.setNotify_field(baseRequestObj.getNotifyOn());
625 jsonNotification.setEndpoint(baseRequestObj.getApplicationNotificationEndpoint());
626 jsonNotification.setUsername(baseRequestObj.getApplicationUsername());
627 jsonNotification.setPassword(baseRequestObj.getApplicationPassword());
628 String pkValue = jsonResponse.getPrimary_key();
630 String[] fullNotifyArr = baseRequestObj.getNotifyOn().split(":");
632 String[] tableArr = fullNotifyArr[0].split("\\.");
633 TableMetadata tableInfo = MusicCore.returnColumnMetadata(tableArr[0], tableArr[1]);
634 DataType primaryIdType = tableInfo.getPrimaryKey().get(0).getType();
635 String primaryId = tableInfo.getPrimaryKey().get(0).getName();
637 Map<String, String> responseBodyMap = baseRequestObj.getResponseBody();
638 Map<String, String> newMap = new HashMap<>();
639 if(responseBodyMap.size() == 1 && responseBodyMap.containsKey("")) {
640 jsonNotification.setResponse_body(newMap);
642 for (Entry<String, String> entry : new HashSet<>(responseBodyMap.entrySet())) {
643 String trimmed = entry.getKey().trim();
644 if (!trimmed.equals(entry.getKey())) {
645 responseBodyMap.remove(entry.getKey());
646 responseBodyMap.put(trimmed, entry.getValue());
650 Set<String> keySet = responseBodyMap.keySet();
651 String cql = "select *";
652 /*for(String keys: keySet) {
653 cql = cql + keys + ",";
655 //cql = cql.substring(0, cql.length()-1);
656 cql = cql + " FROM "+fullNotifyArr[0]+" WHERE "+primaryId+" = ?";
657 logger.info("CQL in constructJsonNotification: "+cql);
658 PreparedQueryObject pQuery = new PreparedQueryObject();
659 pQuery.appendQueryString(cql);
660 pQuery.addValue(MusicUtil.convertToActualDataType(primaryIdType, pkValue));
661 Row row = MusicCore.get(pQuery).one();
663 ColumnDefinitions colInfo = row.getColumnDefinitions();
664 for (Definition definition : colInfo) {
665 String colName = definition.getName();
666 if(keySet.contains(colName)) {
667 DataType colType = definition.getType();
668 Object valueObj = MusicCore.getDSHandle().getColValue(row, colName, colType);
669 Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
670 logger.info(colName+" : "+valueString);
671 newMap.put(colName, valueString.toString());
672 keySet.remove(colName);
676 if(! keySet.isEmpty()) {
677 Iterator<String> iterator = keySet.iterator();
678 while (iterator.hasNext()) {
679 String element = iterator.next();
680 if(element != null && element.length() > 0)
681 newMap.put(element,"COLUMN_NOT_FOUND");
685 if("delete".equals(jsonResponse.getOperation()) || newMap.isEmpty()) {
686 newMap.put(primaryId, pkValue);
688 jsonNotification.setResponse_body(newMap);
690 } catch(Exception e) {
693 return jsonNotification;
696 private void constructJsonCallbackFromCache() throws Exception{
697 PreparedQueryObject pQuery = new PreparedQueryObject();
698 JsonCallback jsonCallback = null;
699 List<String> notifyList = new java.util.ArrayList<>();
701 "select id, endpoint_userid, endpoint_password, notify_to_endpoint, notify_insert_on,"
702 + " notify_delete_on, notify_update_on, request, notifyon from admin.notification_master allow filtering";
703 pQuery.appendQueryString(cql);
704 //pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), fullTable));
705 logger.info("Query: "+pQuery.getQuery());
707 ResultSet rs = MusicCore.get(pQuery);
708 Iterator<Row> it = rs.iterator();
709 while (it.hasNext()) {
710 Row row = (Row) it.next();
711 String endpoint = row.getString("notify_to_endpoint");
712 String username = row.getString("endpoint_userid");
713 ByteBuffer passwordBytes = row.getBytes("endpoint_password");
714 String insert = row.getString("notify_insert_on");
715 String delete = row.getString("notify_delete_on");
716 String update = row.getString("notify_update_on");
717 String request = row.getString("request");
718 String notifyon = row.getString("notifyon");
719 String uuid = row.getUUID("id").toString();
720 notifyList.add(notifyon);
721 jsonCallback = new JsonCallback();
722 jsonCallback.setApplicationNotificationEndpoint(endpoint);
724 Charset charset = Charset.forName("ISO-8859-1");
725 String decodedPwd = charset.decode(passwordBytes).toString();
726 jsonCallback.setApplicationPassword(decodedPwd);
727 jsonCallback.setApplicationUsername(username);
728 jsonCallback.setNotifyOn(notifyon);
729 jsonCallback.setNotifyWhenInsertsIn(insert);
730 jsonCallback.setNotifyWhenDeletesIn(delete);
731 jsonCallback.setNotifyWhenChangeIn(update);
732 jsonCallback.setUuid(uuid);
733 logger.info("From DB. Saved request_body: "+request);
734 request = request.substring(1, request.length()-1);
735 String[] keyValuePairs = request.split(",");
736 Map<String,String> responseBody = new HashMap<>();
738 for(String pair : keyValuePairs) {
739 String[] entry = pair.split("=");
741 if(entry.length == 2)
743 responseBody.put(entry[0], val);
745 logger.info("After parsing. Saved request_body: "+responseBody);
746 jsonCallback.setResponseBody(responseBody);
747 logger.info("Updating Cache with updateCallBackCache: "+notifyon+ " :::: "+jsonCallback);
748 CachingUtil.updateCallBackCache(notifyon, jsonCallback);
750 CachingUtil.updateCallbackNotifyList(notifyList);
754 @Path("/onboardCallback")
755 @Produces(MediaType.APPLICATION_JSON)
756 @Consumes(MediaType.APPLICATION_JSON)
757 public Response addCallback(JsonNotification jsonNotification) {
758 Map<String, Object> resultMap = new HashMap<>();
759 ResponseBuilder response =
760 Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
761 String username = jsonNotification.getUsername();
762 String password = jsonNotification.getPassword();
763 String endpoint = jsonNotification.getEndpoint();
764 String notify_field = jsonNotification.getNotify_field();
765 Map<String, String> responseBody = jsonNotification.getResponse_body();
766 String triggerName = jsonNotification.getTriggerName();
767 if(triggerName == null || triggerName.length() == 0)
768 triggerName = "MusicTrigger";
770 /*JsonCallback callBackCache = CachingUtil.getCallBackCache(notify_field);
771 if(callBackCache != null) {
772 resultMap.put("Exception", "The notification property has already been onboarded.");
773 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
776 String[] allFields = notify_field.split(":");
777 String inserts = null;
778 String updates = null;
779 String deletes = null;
780 String tableName = null;
781 if(allFields.length >= 2) {
782 inserts = updates = notify_field;
783 } else if(allFields.length == 1) {
784 inserts = deletes = notify_field;;
786 tableName = allFields[0];
787 String cql = "CREATE TRIGGER IF NOT EXISTS musictrigger ON "+tableName+" Using '"+triggerName+"'";
788 PreparedQueryObject pQuery = new PreparedQueryObject();
790 String uuid = CachingUtil.generateUUID();
792 pQuery.appendQueryString(
793 "INSERT INTO admin.notification_master (id, endpoint_userid, endpoint_password, notify_to_endpoint, "
794 + "notifyon, notify_insert_on, notify_delete_on, notify_update_on, request, current_notifier) VALUES (?,?,?,?,?,?,?,?,?,?)");
795 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
796 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), username));
797 Charset charset = Charset.forName("ISO-8859-1");
798 ByteBuffer decodedPwd = charset.encode(password);
799 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.blob(), decodedPwd.array()));
800 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), endpoint));
801 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), notify_field));
802 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), inserts));
803 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), deletes));
804 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), updates));
805 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), responseBody));
806 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), MusicCore.getMyHostId()));
807 MusicCore.nonKeyRelatedPut(pQuery, MusicUtil.EVENTUAL);
808 JsonCallback jsonCallback = new JsonCallback();
809 jsonCallback.setUuid(uuid);
810 jsonCallback.setApplicationNotificationEndpoint(endpoint);
811 jsonCallback.setApplicationPassword(password);
812 jsonCallback.setApplicationUsername(username);
813 jsonCallback.setNotifyOn(notify_field);
814 jsonCallback.setNotifyWhenChangeIn(updates);
815 jsonCallback.setNotifyWhenDeletesIn(deletes);
816 jsonCallback.setNotifyWhenInsertsIn(inserts);
817 jsonCallback.setResponseBody(responseBody);
818 CachingUtil.updateCallBackCache(notify_field, jsonCallback);
819 logger.info("Cache updated ");
820 pQuery = new PreparedQueryObject();
821 pQuery.appendQueryString(cql);
822 ResultType nonKeyRelatedPut = MusicCore.nonKeyRelatedPut(pQuery, MusicUtil.EVENTUAL);
823 logger.info(EELFLoggerDelegate.applicationLogger, "Created trigger");
824 //callBackCache.put(jsonCallback.getApplicationName(), jsonMap);
825 } catch (InvalidQueryException e) {
826 logger.error(EELFLoggerDelegate.errorLogger,"Exception callback_api table not configured."+e.getMessage());
827 resultMap.put("Exception", "Please make sure admin.notification_master table is configured.");
828 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
829 } catch(Exception e) {
831 resultMap.put("Exception", "Exception Occured.");
832 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
834 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Callback api successfully registered").toMap()).build();
837 /*public String encodePwd(String password) {
838 return Base64.getEncoder().encodeToString(password.getBytes());
841 public String decodePwd(String password) {
842 byte[] bytes = Base64.getDecoder().decode(password);
843 return new String(bytes);