Update swagger.json and other updates.
[music.git] / src / main / java / org / onap / music / rest / RestMusicAdminAPI.java
1 /*
2  * ============LICENSE_START==========================================
3  * org.onap.music
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
10  * 
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  * 
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.
18  * 
19  * ============LICENSE_END=============================================
20  * ====================================================================
21  */
22 package org.onap.music.rest;
23
24
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.UUID;
32
33 import javax.ws.rs.Consumes;
34 import javax.ws.rs.DELETE;
35 import javax.ws.rs.POST;
36 import javax.ws.rs.PUT;
37 import javax.ws.rs.Path;
38 import javax.ws.rs.Produces;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.Response;
41 import javax.ws.rs.core.Response.ResponseBuilder;
42 import javax.ws.rs.core.Response.Status;
43
44 import org.codehaus.jackson.map.ObjectMapper;
45 import org.mindrot.jbcrypt.BCrypt;
46 import org.onap.music.datastore.PreparedQueryObject;
47 import org.onap.music.datastore.jsonobjects.JSONCallbackResponse;
48 import org.onap.music.datastore.jsonobjects.JSONObject;
49 import org.onap.music.datastore.jsonobjects.JsonCallback;
50 import org.onap.music.datastore.jsonobjects.JsonNotification;
51 import org.onap.music.datastore.jsonobjects.JsonOnboard;
52 import org.onap.music.eelf.logging.EELFLoggerDelegate;
53 import org.onap.music.eelf.logging.format.AppMessages;
54 import org.onap.music.eelf.logging.format.ErrorSeverity;
55 import org.onap.music.eelf.logging.format.ErrorTypes;
56 //import org.onap.music.main.CacheAccess;
57 import org.onap.music.main.CachingUtil;
58 import org.onap.music.main.MusicCore;
59 import org.onap.music.main.MusicUtil;
60 import org.onap.music.main.ResultType;
61 import org.onap.music.main.ReturnType;
62 import org.onap.music.response.jsonobjects.JsonResponse;
63
64 import com.datastax.driver.core.DataType;
65 import com.datastax.driver.core.ResultSet;
66 import com.datastax.driver.core.Row;
67 import com.datastax.driver.core.exceptions.InvalidQueryException;
68 import com.sun.jersey.api.client.Client;
69 import com.sun.jersey.api.client.ClientResponse;
70 import com.sun.jersey.api.client.WebResource;
71 import com.sun.jersey.core.util.Base64;
72
73 import io.swagger.annotations.Api;
74 import io.swagger.annotations.ApiOperation;
75 import com.datastax.driver.core.TableMetadata;
76
77 import javax.ws.rs.core.HttpHeaders;
78 import javax.ws.rs.core.MediaType;
79 import com.datastax.driver.core.ColumnDefinitions;
80 import com.datastax.driver.core.ColumnDefinitions.Definition;
81 import com.datastax.driver.core.TableMetadata;
82 import java.util.Base64.Encoder; 
83 import java.util.Base64.Decoder;
84
85 @Path("/v2/admin")
86 // @Path("/v{version: [0-9]+}/admin")
87 // @Path("/admin")
88 @Api(value = "Admin Api", hidden = true)
89 public class RestMusicAdminAPI {
90     private static EELFLoggerDelegate logger =
91                     EELFLoggerDelegate.getLogger(RestMusicAdminAPI.class);
92     /*
93      * API to onboard an application with MUSIC. This is the mandatory first step.
94      * 
95      */
96     @POST
97     @Path("/onboardAppWithMusic")
98     @ApiOperation(value = "Onboard application", response = String.class)
99     @Consumes(MediaType.APPLICATION_JSON)
100     @Produces(MediaType.APPLICATION_JSON)
101     public Response onboardAppWithMusic(JsonOnboard jsonObj) throws Exception {
102         ResponseBuilder response =
103                         Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
104         Map<String, Object> resultMap = new HashMap<>();
105         String appName = jsonObj.getAppname();
106         String userId = jsonObj.getUserId();
107         String isAAF = jsonObj.getIsAAF();
108         String password = jsonObj.getPassword();
109         if (appName == null || userId == null || isAAF == null || password == null) {
110             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
111                             ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
112             resultMap.put("Exception",
113                             "Unauthorized: Please check the request parameters. Some of the required values appName(ns), userId, password, isAAF are missing.");
114             return Response.status(Status.UNAUTHORIZED).entity(resultMap).build();
115         }
116
117         PreparedQueryObject pQuery = new PreparedQueryObject();
118         pQuery.appendQueryString(
119                         "select uuid from admin.keyspace_master where application_name = ? allow filtering");
120         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
121         ResultSet rs = MusicCore.get(pQuery);
122         if (!rs.all().isEmpty()) {
123             resultMap.put("Exception", "Application " + appName
124                             + " has already been onboarded. Please contact admin.");
125             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
126         }
127
128         pQuery = new PreparedQueryObject();
129         String uuid = CachingUtil.generateUUID();
130         pQuery.appendQueryString(
131                         "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
132                                         + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)");
133         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
134         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
135                         MusicUtil.DEFAULTKEYSPACENAME));
136         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
137         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
138         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), password));
139         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
140         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
141
142         String returnStr = MusicCore.eventualPut(pQuery).toString();
143         if (returnStr.contains("Failure")) {
144             resultMap.put("Exception",
145                             "Oops. Something wrong with onboarding process. Please retry later or contact admin.");
146             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
147         }
148         CachingUtil.updateisAAFCache(appName, isAAF);
149         resultMap.put("Success", "Your application " + appName + " has been onboarded with MUSIC.");
150         resultMap.put("Generated AID", uuid);
151         return Response.status(Status.OK).entity(resultMap).build();
152     }
153
154
155     @POST
156     @Path("/search")
157     @ApiOperation(value = "Search Onboard application", response = String.class)
158     @Consumes(MediaType.APPLICATION_JSON)
159     @Produces(MediaType.APPLICATION_JSON)
160     public Response getOnboardedInfoSearch(JsonOnboard jsonObj) throws Exception {
161         Map<String, Object> resultMap = new HashMap<>();
162         ResponseBuilder response =
163                         Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
164         String appName = jsonObj.getAppname();
165         String uuid = jsonObj.getAid();
166         String isAAF = jsonObj.getIsAAF();
167
168         if (appName == null && uuid == null && isAAF == null) {
169             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
170                             ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
171             resultMap.put("Exception",
172                             "Unauthorized: Please check the request parameters. Enter atleast one of the following parameters: appName(ns), aid, isAAF.");
173             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
174         }
175
176         PreparedQueryObject pQuery = new PreparedQueryObject();
177         String cql = "select uuid, keyspace_name from admin.keyspace_master where ";
178         if (appName != null)
179             cql = cql + "application_name = ? AND ";
180         if (uuid != null)
181             cql = cql + "uuid = ? AND ";
182         if (isAAF != null)
183             cql = cql + "is_aaf = ?";
184
185         if (cql.endsWith("AND "))
186             cql = cql.trim().substring(0, cql.length() - 4);
187         logger.info("Query in callback is: " + cql);
188         cql = cql + " allow filtering";
189         pQuery.appendQueryString(cql);
190         if (appName != null)
191             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
192         if (uuid != null)
193             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
194         if (isAAF != null)
195             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(),
196                             Boolean.parseBoolean(isAAF)));
197         ResultSet rs = MusicCore.get(pQuery);
198         Iterator<Row> it = rs.iterator();
199         while (it.hasNext()) {
200             Row row = (Row) it.next();
201             resultMap.put(row.getUUID("uuid").toString(), row.getString("keyspace_name"));
202         }
203         if (resultMap.isEmpty()) {
204             if (uuid != null) {
205                 resultMap.put("Exception",
206                                 "Please make sure Aid is correct and application is onboarded.");
207                 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
208             } else {
209                 resultMap.put("Exception",
210                                 "Application is not onboarded. Please make sure all the information is correct.");
211                 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
212             }
213         }
214         return Response.status(Status.OK).entity(resultMap).build();
215     }
216
217
218     @DELETE
219     @Path("/onboardAppWithMusic")
220     @ApiOperation(value = "Delete Onboard application", response = String.class)
221     @Consumes(MediaType.APPLICATION_JSON)
222     @Produces(MediaType.APPLICATION_JSON)
223     public Response deleteOnboardApp(JsonOnboard jsonObj) throws Exception {
224         Map<String, Object> resultMap = new HashMap<>();
225         ResponseBuilder response =
226                         Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
227         String appName = jsonObj.getAppname();
228         String aid = jsonObj.getAid();
229         PreparedQueryObject pQuery = new PreparedQueryObject();
230         String consistency = MusicUtil.EVENTUAL;;
231         if (appName == null && aid == null) {
232             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
233                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
234             resultMap.put("Exception", "Please make sure either appName(ns) or Aid is present");
235             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
236         }
237         if (aid != null) {
238             pQuery.appendQueryString(
239                             "SELECT keyspace_name FROM admin.keyspace_master WHERE uuid = ?");
240             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
241                             UUID.fromString(aid)));
242             Row row = MusicCore.get(pQuery).one();
243             if (row != null) {
244                 String ks = row.getString("keyspace_name");
245                 if (!ks.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
246                     PreparedQueryObject queryObject = new PreparedQueryObject();
247                     queryObject.appendQueryString("DROP KEYSPACE IF EXISTS " + ks + ";");
248                     MusicCore.nonKeyRelatedPut(queryObject, consistency);
249                 }
250             }
251             pQuery = new PreparedQueryObject();
252             pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ? IF EXISTS");
253             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
254                             UUID.fromString(aid)));
255             ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
256             if (result == ResultType.SUCCESS) {
257                 resultMap.put("Success", "Your application has been deleted successfully");
258             } else {
259                 resultMap.put("Exception",
260                                 "Oops. Something went wrong. Please make sure Aid is correct or Application is onboarded");
261                 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
262                                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
263                 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
264
265             }
266             return Response.status(Status.OK).entity(resultMap).build();
267         }
268
269         pQuery.appendQueryString(
270                         "select uuid from admin.keyspace_master where application_name = ? allow filtering");
271         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
272         ResultSet rs = MusicCore.get(pQuery);
273         List<Row> rows = rs.all();
274         String uuid = null;
275         if (rows.size() == 0) {
276             resultMap.put("Exception",
277                             "Application not found. Please make sure Application exists.");
278             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
279                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
280             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
281         } else if (rows.size() == 1) {
282             uuid = rows.get(0).getUUID("uuid").toString();
283             pQuery = new PreparedQueryObject();
284             pQuery.appendQueryString(
285                             "SELECT keyspace_name FROM admin.keyspace_master WHERE uuid = ?");
286             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
287                             UUID.fromString(uuid)));
288             Row row = MusicCore.get(pQuery).one();
289             String ks = row.getString("keyspace_name");
290             if (!ks.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
291                 PreparedQueryObject queryObject = new PreparedQueryObject();
292                 queryObject.appendQueryString("DROP KEYSPACE " + ks + ";");
293                 MusicCore.nonKeyRelatedPut(queryObject, consistency);
294             }
295
296             pQuery = new PreparedQueryObject();
297             pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
298             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
299                             UUID.fromString(uuid)));
300             MusicCore.eventualPut(pQuery);
301             resultMap.put("Success", "Your application " + appName + " has been deleted.");
302             return Response.status(Status.OK).entity(resultMap).build();
303         } else {
304             resultMap.put("Failure",
305                             "More than one Aid exists for this application, so please provide Aid.");
306             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MULTIPLERECORDS,
307                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
308             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
309         }
310     }
311
312
313     @PUT
314     @Path("/onboardAppWithMusic")
315     @ApiOperation(value = "Update Onboard application", response = String.class)
316     @Consumes(MediaType.APPLICATION_JSON)
317     @Produces(MediaType.APPLICATION_JSON)
318     public Response updateOnboardApp(JsonOnboard jsonObj) throws Exception {
319         Map<String, Object> resultMap = new HashMap<>();
320         ResponseBuilder response =
321                         Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
322         String aid = jsonObj.getAid();
323         String appName = jsonObj.getAppname();
324         String userId = jsonObj.getUserId();
325         String isAAF = jsonObj.getIsAAF();
326         String password = jsonObj.getPassword();
327         String consistency = "eventual";
328         PreparedQueryObject pQuery;
329
330         if (aid == null) {
331             resultMap.put("Exception", "Please make sure Aid is present");
332             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
333                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
334             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
335         }
336
337         if (appName == null && userId == null && password == null && isAAF == null) {
338             resultMap.put("Exception",
339                             "No parameters found to update. Please update atleast one parameter.");
340             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
341                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
342             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
343         }
344
345         if (appName != null) {
346             pQuery = new PreparedQueryObject();
347             pQuery.appendQueryString(
348                             "select uuid from admin.keyspace_master where application_name = ? allow filtering");
349             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
350             ResultSet rs = MusicCore.get(pQuery);
351             if (!rs.all().isEmpty()) {
352                 resultMap.put("Exception", "Application " + appName
353                                 + " has already been onboarded. Please contact admin.");
354                 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.ALREADYEXIST,
355                                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
356                 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
357             }
358         }
359
360         pQuery = new PreparedQueryObject();
361         StringBuilder preCql = new StringBuilder("UPDATE admin.keyspace_master SET ");
362         if (appName != null)
363             preCql.append(" application_name = ?,");
364         if (userId != null)
365             preCql.append(" username = ?,");
366         if (password != null)
367             preCql.append(" password = ?,");
368         if (isAAF != null)
369             preCql.append(" is_aaf = ?,");
370         preCql.deleteCharAt(preCql.length() - 1);
371         preCql.append(" WHERE uuid = ? IF EXISTS");
372         pQuery.appendQueryString(preCql.toString());
373         if (appName != null)
374             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
375         if (userId != null)
376             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
377         if (password != null)
378             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt())));
379         if (isAAF != null)
380             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
381
382         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), UUID.fromString(aid)));
383         ResultType result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
384
385         if (result == ResultType.SUCCESS) {
386             resultMap.put("Success", "Your application has been updated successfully");
387         } else {
388             resultMap.put("Exception",
389                             "Oops. Something went wrong. Please make sure Aid is correct and application is onboarded");
390             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
391                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
392             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
393         }
394
395         return Response.status(Status.OK).entity(resultMap).build();
396     }
397
398     Client client = Client.create();
399     
400     @POST
401     @Path("/callbackOps")
402     @Produces(MediaType.APPLICATION_JSON)
403     @Consumes(MediaType.APPLICATION_JSON)
404         public Response callbackOps(final JSONObject inputJsonObj) {
405          // {"keyspace":"conductor","full_table":"conductor.plans","changeValue":{"conductor.plans.status":"Who??","position":"3"},"operation":"update","table_name":"plans","primary_key":"3"}
406         Map<String, Object> resultMap = new HashMap<>();
407         new Thread(new Runnable() {
408             public void run() {
409                 makeAsyncCall(inputJsonObj);
410             }
411         }).start();
412             
413                 return Response.status(Status.OK).entity(resultMap).build();
414         }
415     
416     private Response makeAsyncCall(JSONObject inputJsonObj) {
417         
418         Map<String, Object> resultMap = new HashMap<>();
419         try {
420                         logger.info("Got notification: " + inputJsonObj.getData());
421                         String dataStr = inputJsonObj.getData();
422                         ObjectMapper mapper = new ObjectMapper();
423                         JSONCallbackResponse jsonResponse = mapper.readValue(dataStr, JSONCallbackResponse.class);
424                         String operation = jsonResponse.getOperation();
425                         Map<String, String> changeValueMap = jsonResponse.getChangeValue();
426                         String primaryKey = jsonResponse.getPrimary_key();
427                         //String full_table = jsonResponse.getFull_table(); //conductor.plans
428                         String field_value = changeValueMap.get("field_value");
429                         if(field_value == null)
430                                 field_value = jsonResponse.getFull_table();
431                         //Get from Cache
432                         JsonCallback baseRequestObj = CachingUtil.getCallBackCache(field_value);
433                         //baseRequestObj = null;
434                         
435                         if(baseRequestObj == null) {
436                                 logger.info("Is cache empty? reconstructing Object from cache..");
437                                 baseRequestObj = constructJsonCallbackFromCache(field_value);
438                         }
439                         if(baseRequestObj == null) {
440                                 resultMap.put("Exception",
441                             "Oops. Something went wrong. Please make sure Callback properties are onboarded.");
442                                 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA,
443                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
444                                 return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
445                         }
446                         
447                         String key = "admin" + "." + "notification_master" + "." + baseRequestObj.getUuid();
448                 String lockId = MusicCore.createLockReference(key);
449                 long lockCreationTime = System.currentTimeMillis();
450                 ReturnType lockAcqResult = MusicCore.acquireLock(key, lockId);
451                 if(! lockAcqResult.getResult().toString().equals("SUCCESS")) {
452                         logger.info("Some other node is notifying the caller..");
453                 }
454                         
455                         logger.info(operation+ ": Operation :: changeValue: "+changeValueMap);
456                         if(operation.equals("update")) {
457                                 String notifyWhenChangeIn = baseRequestObj.getNotifyWhenChangeIn(); // conductor.plans.status
458                                 logger.info("**********notifyWhenChangeIn: "+notifyWhenChangeIn);
459                                 if(field_value.equals(notifyWhenChangeIn)) {
460                                         logger.info("********** notifyting the endpoint: "+baseRequestObj.getApplicationNotificationEndpoint());
461                                         notifyCallBackAppl(jsonResponse, baseRequestObj);
462                                 }
463                                 
464                         } else if(operation.equals("delete")) {
465                                 String notifyWhenDeletesIn = baseRequestObj.getNotifyWhenDeletesIn(); // conductor.plans.status
466                                 logger.info("**********notifyWhenDeletesIn: "+notifyWhenDeletesIn);
467                                 if(field_value.equals(notifyWhenDeletesIn)) {
468                                         logger.info("********** notifyting the endpoint: "+baseRequestObj.getApplicationNotificationEndpoint());
469                                         notifyCallBackAppl(jsonResponse, baseRequestObj);
470                                 }
471                         } else if(operation.equals("insert")) {
472                                 String notifyWhenInsertsIn = baseRequestObj.getNotifyWhenInsertsIn(); // conductor.plans.status
473                                 logger.info("**********notifyWhenInsertsIn: "+notifyWhenInsertsIn);
474                                 if(field_value.equals(notifyWhenInsertsIn)) {
475                                         logger.info("********** notifyting the endpoint: "+baseRequestObj.getApplicationNotificationEndpoint());
476                                         notifyCallBackAppl(jsonResponse, baseRequestObj);
477                                 }
478                         }
479                         MusicCore.releaseLock(lockId, true);    
480             } catch(Exception e) {
481             e.printStackTrace();
482             logger.info("Exception...");
483         }
484         logger.info(">>> callback is completed. Notification was sent from Music...");
485         return Response.status(Status.OK).entity(resultMap).build();
486     }
487     
488     private void notifyCallBackAppl(JSONCallbackResponse jsonResponse, JsonCallback baseRequestObj) {
489         int notifytimeout = MusicUtil.getNotifyTimeout();
490         int notifyinterval = MusicUtil.getNotifyInterval();
491         String endpoint = baseRequestObj.getApplicationNotificationEndpoint();
492         String username = baseRequestObj.getApplicationUsername();
493         String password = baseRequestObj.getApplicationPassword();
494         JsonNotification jsonNotification = constructJsonNotification(jsonResponse, baseRequestObj);
495         jsonNotification.setOperation_type(jsonResponse.getOperation());
496         logger.info("Response sent is: "+jsonNotification);
497         WebResource webResource = client.resource(endpoint);
498         String authData = username+":"+password;
499         byte[] plainCredsBytes = authData.getBytes();
500         byte[] base64CredsBytes = Base64.encode(plainCredsBytes);
501         String base64Creds = new String(base64CredsBytes);
502         Map<String, String> response_body = baseRequestObj.getResponseBody();
503         ClientResponse response = null;
504         try { 
505                 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
506             .post(ClientResponse.class, jsonNotification);
507         } catch (com.sun.jersey.api.client.ClientHandlerException chf) {
508                 boolean ok = false;
509                 logger.info("Is Service down?");
510                 long now= System.currentTimeMillis();
511                 long end = now+notifytimeout;
512                 while(! ok) {
513                         logger.info("retrying since error in notifying callback..");
514                         try {
515                                 response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
516                             .post(ClientResponse.class, jsonNotification);
517                                 if(response.getStatus() == 200) ok = true;
518                         }catch (Exception e) {
519                                 System.err.println("Is response null: "+response==null);
520                                 System.err.println("Retry until "+(end-System.currentTimeMillis()));
521                                 if(response == null && System.currentTimeMillis() < end) ok = false;
522                                 else ok = true;
523                                 try{ Thread.sleep(notifyinterval); } catch(Exception e1) {}
524                         }
525                 }
526         }
527         response.bufferEntity();
528         String responseStr = response.getEntity(String.class);
529         logger.info(">>>>> Response from Notified client: "+responseStr);
530         
531         if(response.getStatus() != 200){
532                 long now= System.currentTimeMillis();
533                 long end = now+30000;
534                 while(response.getStatus() != 200 && System.currentTimeMillis() < end) {
535                         logger.info("retrying since error in notifying callback..");
536                         response = webResource.header("Authorization", "Basic " + base64Creds).accept("application/json").type("application/json")
537                             .post(ClientResponse.class, jsonNotification);
538                 }
539             logger.error("Exception while notifying.. "+response.getStatus());
540         }
541     }
542     
543     private JsonNotification constructJsonNotification(JSONCallbackResponse jsonResponse, JsonCallback baseRequestObj) {
544         
545         JsonNotification jsonNotification = new JsonNotification();
546         try {
547                 jsonNotification.setNotify_field(baseRequestObj.getNotifyOn());
548                 jsonNotification.setEndpoint(baseRequestObj.getApplicationNotificationEndpoint());
549                 jsonNotification.setUsername(baseRequestObj.getApplicationUsername());
550                 jsonNotification.setPassword(baseRequestObj.getApplicationPassword());
551                 String pkValue = jsonResponse.getPrimary_key();
552                 
553                 String[] fullNotifyArr = baseRequestObj.getNotifyOn().split(":");
554                 
555                 String[] tableArr = fullNotifyArr[0].split("\\.");
556                 TableMetadata tableInfo = MusicCore.returnColumnMetadata(tableArr[0], tableArr[1]);
557                         DataType primaryIdType = tableInfo.getPrimaryKey().get(0).getType();
558                         String primaryId = tableInfo.getPrimaryKey().get(0).getName();
559                         logger.info(">>>>>>> Primary Id: "+primaryId);
560                         
561                         Map<String, String> responseBodyMap = baseRequestObj.getResponseBody();
562                 Set<String> keySet = responseBodyMap.keySet();
563                 /*for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
564                                 DataType colType = null;
565                     try {
566                         colType = tableInfo.getColumn(entry.getKey()).getType();
567                     } catch(NullPointerException ex) {
568                         
569                     }
570                 }*/
571                         
572                 
573                 String cql = "select ";
574                 for(String keys: keySet) {
575                         cql = cql + keys + ",";
576                 }
577                 cql = cql.substring(0, cql.length()-1);
578                 cql = cql + " FROM "+fullNotifyArr[0]+" WHERE "+primaryId+" = ?";
579                 logger.info("CQL in constructJsonNotification: "+cql);
580                 PreparedQueryObject pQuery = new PreparedQueryObject();
581                 pQuery.appendQueryString(cql);
582                 pQuery.addValue(MusicUtil.convertToActualDataType(primaryIdType, pkValue));
583                 Row row = MusicCore.get(pQuery).one();
584                 Map<String, String> newMap = new HashMap<>();
585                 if(row != null) {
586                         for(String keys: keySet) {
587                                 String value = null;
588                                 logger.info("responseBodyMap: "+responseBodyMap.toString());
589                                 logger.info(">>>>>>>> converting <<<<<<<<<<<< "+keys + " : "+responseBodyMap.get(keys)+ ":" +responseBodyMap.get(keys).equals("uuid"));
590                                 if(responseBodyMap.get(keys).equals("uuid"))
591                                         value = row.getUUID(keys).toString();
592                                 else if (responseBodyMap.get(keys).equals("text"))
593                                         value = row.getString(keys);
594                                 /*else if (responseBodyMap.get(keys).contains("int"))
595                                         value = row.getLong(keys).toString();*/
596                                 newMap.put(keys, value);
597                         }
598                 }
599                 if("delete".equals(jsonResponse.getOperation())) {
600                         newMap.put(primaryId, pkValue);
601                 }
602                 jsonNotification.setResponse_body(newMap);
603         } catch(Exception e) {
604                 e.printStackTrace();
605         }
606         return jsonNotification;
607     }
608     
609     private JsonCallback constructJsonCallbackFromCache(String fullTable) throws Exception{
610         PreparedQueryObject pQuery = new PreparedQueryObject();
611                 JsonCallback jsonCallback = new JsonCallback();
612                 String cql = 
613                 "select id, endpoint_userid, endpoint_password, notify_to_endpoint, notify_insert_on,"
614                 + " notify_delete_on, notify_update_on, request from admin.notification_master where notifyon = ? allow filtering";
615         pQuery.appendQueryString(cql);
616         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), fullTable));
617         logger.info("Query: "+pQuery.getQuery() + " : "+fullTable);
618         
619         Row row = MusicCore.get(pQuery).one();
620         if(row != null) {
621                 String endpoint = row.getString("notify_to_endpoint");
622             String username = row.getString("endpoint_userid");
623             String password = row.getString("endpoint_password");
624             String insert = row.getString("notify_insert_on");
625             String delete = row.getString("notify_delete_on");
626             String update = row.getString("notify_update_on");
627             String request = row.getString("request");
628             String uuid = row.getUUID("id").toString();
629             jsonCallback.setApplicationNotificationEndpoint(endpoint);
630             jsonCallback.setApplicationPassword(password);
631             jsonCallback.setApplicationUsername(username);
632             jsonCallback.setNotifyOn(fullTable);
633             jsonCallback.setNotifyWhenInsertsIn(insert);
634             jsonCallback.setNotifyWhenDeletesIn(delete);
635             jsonCallback.setNotifyWhenChangeIn(update);
636             jsonCallback.setUuid(uuid);
637             logger.info("From DB. Saved request_body: "+request);
638             request = request.substring(1, request.length()-1);           
639             String[] keyValuePairs = request.split(",");              
640             Map<String,String> responseBody = new HashMap<>();               
641
642             for(String pair : keyValuePairs) {
643                 String[] entry = pair.split("="); 
644                 String val = "";
645                 if(entry.length == 2)
646                         val = entry[1];
647                 responseBody.put(entry[0], val);          
648             }
649             logger.info("After parsing. Saved request_body: "+responseBody);
650             jsonCallback.setResponseBody(responseBody);
651         }
652         return jsonCallback;
653     }
654
655     @POST
656     @Path("/onboardCallback")
657     @Produces(MediaType.APPLICATION_JSON)
658     @Consumes(MediaType.APPLICATION_JSON)
659     public Response addCallback(JsonNotification jsonNotification) {
660         Map<String, Object> resultMap = new HashMap<>();
661         ResponseBuilder response =
662                         Response.noContent().header("X-latestVersion", MusicUtil.getVersion());
663         String username = jsonNotification.getUsername();
664         String password = jsonNotification.getPassword();
665         String endpoint = jsonNotification.getEndpoint();
666         String notify_field = jsonNotification.getNotify_field();
667         Map<String, String> responseBody = jsonNotification.getResponse_body();
668         
669         String[] allFields = notify_field.split(":");
670         String inserts = null;
671         String updates = null;
672         String deletes = null;
673         if(allFields.length >= 2) {
674                 inserts = updates = notify_field;
675         } else if(allFields.length == 1) {
676                 inserts = deletes = notify_field;;
677         }
678                         
679         PreparedQueryObject pQuery = new PreparedQueryObject();
680         /*if (username == null || password == null || endpoint == null) {
681             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO,
682                             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
683             resultMap.put("Exception",
684                             "Please check the request parameters. Some of the required values are missing.");
685             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
686         }*/
687         String uuid = CachingUtil.generateUUID();
688         try {
689                 pQuery.appendQueryString(
690                                 "INSERT INTO admin.notification_master (id, endpoint_userid, endpoint_password, notify_to_endpoint, "
691                                                 + "notifyon, notify_insert_on, notify_delete_on, notify_update_on, request, current_notifier) VALUES (?,?,?,?,?,?,?,?,?,?)");
692                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
693                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), username));
694                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), password));
695                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), endpoint));
696                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), notify_field));
697                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), inserts));
698                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), deletes));
699                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), updates));
700                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), responseBody));
701                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), "UNKNOWN"));
702                 MusicCore.nonKeyRelatedPut(pQuery, MusicUtil.EVENTUAL);
703                 JsonCallback jsonCallback = new JsonCallback();
704                 jsonCallback.setUuid(uuid);
705                 jsonCallback.setApplicationNotificationEndpoint(endpoint);
706                 jsonCallback.setApplicationPassword(password);
707                 jsonCallback.setApplicationUsername(username);
708                 jsonCallback.setNotifyOn(notify_field);
709                 jsonCallback.setNotifyWhenChangeIn(updates);
710                 jsonCallback.setNotifyWhenDeletesIn(deletes);
711                 jsonCallback.setNotifyWhenInsertsIn(inserts);
712                 jsonCallback.setResponseBody(responseBody);
713                 CachingUtil.updateCallBackCache(notify_field, jsonCallback);
714                 logger.info("Cache updated ");
715         //callBackCache.put(jsonCallback.getApplicationName(), jsonMap);
716         } catch (InvalidQueryException e) {
717             logger.error(EELFLoggerDelegate.errorLogger,"Exception callback_api table not configured."+e.getMessage());
718             resultMap.put("Exception", "Please make sure admin.notification_master table is configured.");
719             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
720         } catch(Exception e) {
721                 e.printStackTrace();
722                 resultMap.put("Exception", "Exception Occured.");
723             return Response.status(Status.BAD_REQUEST).entity(resultMap).build();
724         }
725        return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Callback api successfully registered").toMap()).build();
726     }
727
728     /*public String encodePwd(String password) {
729         return Base64.getEncoder().encodeToString(password.getBytes());
730     }
731     
732     public String decodePwd(String password) {
733         byte[] bytes = Base64.getDecoder().decode(password); 
734         return new String(bytes);
735     }*/
736 }