various Updates
[music.git] / src / main / java / org / onap / music / main / MusicCore.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.main;
23
24
25 import java.io.StringWriter;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.StringTokenizer;
29
30 import org.apache.zookeeper.KeeperException;
31 import org.apache.zookeeper.KeeperException.NoNodeException;
32 import org.onap.music.datastore.MusicDataStore;
33 import org.onap.music.datastore.PreparedQueryObject;
34 import org.onap.music.datastore.jsonobjects.JsonKeySpace;
35 import org.onap.music.eelf.logging.EELFLoggerDelegate;
36 import org.onap.music.eelf.logging.format.AppMessages;
37 import org.onap.music.eelf.logging.format.ErrorSeverity;
38 import org.onap.music.eelf.logging.format.ErrorTypes;
39 import org.onap.music.exceptions.MusicLockingException;
40 import org.onap.music.exceptions.MusicQueryException;
41 import org.onap.music.exceptions.MusicServiceException;
42 import org.onap.music.lockingservice.MusicLockState;
43 import org.onap.music.lockingservice.MusicLockState.LockStatus;
44 import org.onap.music.lockingservice.MusicLockingService;
45
46 import com.datastax.driver.core.ColumnDefinitions;
47 import com.datastax.driver.core.ColumnDefinitions.Definition;
48 import com.datastax.driver.core.DataType;
49 import com.datastax.driver.core.ResultSet;
50 import com.datastax.driver.core.Row;
51 import com.datastax.driver.core.TableMetadata;
52
53 /**
54  * This class .....
55  * 
56  *
57  */
58 public class MusicCore {
59
60     public static MusicLockingService mLockHandle = null;
61     public static MusicDataStore mDstoreHandle = null;
62     private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicCore.class);
63
64     public static class Condition {
65         Map<String, Object> conditions;
66         PreparedQueryObject selectQueryForTheRow;
67
68         public Condition(Map<String, Object> conditions, PreparedQueryObject selectQueryForTheRow) {
69             this.conditions = conditions;
70             this.selectQueryForTheRow = selectQueryForTheRow;
71         }
72
73         public boolean testCondition() throws Exception {
74             // first generate the row
75             ResultSet results = quorumGet(selectQueryForTheRow);
76             Row row = results.one();
77             return getDSHandle().doesRowSatisfyCondition(row, conditions);
78         }
79     }
80
81
82     public static MusicLockingService getLockingServiceHandle() throws MusicLockingException {
83         logger.info(EELFLoggerDelegate.applicationLogger,"Acquiring lock store handle");
84         long start = System.currentTimeMillis();
85
86         if (mLockHandle == null) {
87             try {
88                 mLockHandle = new MusicLockingService();
89             } catch (Exception e) {
90                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.LOCKHANDLE,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
91                 throw new MusicLockingException("Failed to aquire Locl store handle " + e);
92             }
93         }
94         long end = System.currentTimeMillis();
95         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to acquire lock store handle:" + (end - start) + " ms");
96         return mLockHandle;
97     }
98
99     /**
100      * 
101      * @param remoteIp
102      * @return
103      */
104     public static MusicDataStore getDSHandle(String remoteIp) {
105         logger.info(EELFLoggerDelegate.applicationLogger,"Acquiring data store handle");
106         long start = System.currentTimeMillis();
107         if (mDstoreHandle == null) {
108             mDstoreHandle = new MusicDataStore(remoteIp);
109         }
110         long end = System.currentTimeMillis();
111         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to acquire data store handle:" + (end - start) + " ms");
112         return mDstoreHandle;
113     }
114
115     /**
116      * 
117      * @return
118      * @throws MusicServiceException 
119      */
120     public static MusicDataStore getDSHandle() throws MusicServiceException {
121         logger.info(EELFLoggerDelegate.applicationLogger,"Acquiring data store handle");
122         long start = System.currentTimeMillis();
123         if (mDstoreHandle == null) {
124             // Quick Fix - Best to put this into every call to getDSHandle?
125             if (! MusicUtil.getMyCassaHost().equals("localhost") ) {
126                 mDstoreHandle = new MusicDataStore(MusicUtil.getMyCassaHost());
127             } else {
128                 mDstoreHandle = new MusicDataStore();
129             }
130         }
131         if(mDstoreHandle.getSession() == null) {
132                 String message = "Connection to Cassandra has not been enstablished."
133                                 + " Please check connection properites and reboot.";
134                 logger.info(EELFLoggerDelegate.applicationLogger, message);
135             throw new MusicServiceException(message);
136         }
137         long end = System.currentTimeMillis();
138         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to acquire data store handle:" + (end - start) + " ms");
139         return mDstoreHandle;
140     }
141
142     public static String createLockReference(String lockName) {
143         logger.info(EELFLoggerDelegate.applicationLogger,"Creating lock reference for lock name:" + lockName);
144         long start = System.currentTimeMillis();
145         String lockId = null;
146         try {
147             lockId = getLockingServiceHandle().createLockId("/" + lockName);
148         } catch (MusicLockingException e) {
149                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.CREATELOCK+lockName,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
150                 
151         }
152         long end = System.currentTimeMillis();
153         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to create lock reference:" + (end - start) + " ms");
154         return lockId;
155     }
156
157     /**
158      * 
159      * @param key
160      * @return
161      */
162     public static boolean isTableOrKeySpaceLock(String key) {
163         String[] splitString = key.split("\\.");
164         if (splitString.length > 2)
165             return false;
166         else
167             return true;
168     }
169
170     /**
171      * 
172      * @param key
173      * @return
174      */
175     public static MusicLockState getMusicLockState(String key) {
176         long start = System.currentTimeMillis();
177         try {
178             String[] splitString = key.split("\\.");
179             String keyspaceName = splitString[0];
180             String tableName = splitString[1];
181             String primaryKey = splitString[2];
182             MusicLockState mls;
183             String lockName = keyspaceName + "." + tableName + "." + primaryKey;
184             mls = getLockingServiceHandle().getLockState(lockName);
185             long end = System.currentTimeMillis();
186             logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to get lock state:" + (end - start) + " ms");
187             return mls;
188         } catch (NullPointerException | MusicLockingException e) {
189                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.INVALIDLOCK,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
190         }
191         return null;
192     }
193
194     public static ReturnType acquireLockWithLease(String key, String lockId, long leasePeriod) {
195         try {
196             long start = System.currentTimeMillis();
197             /* check if the current lock has exceeded its lease and if yes, release that lock */
198             MusicLockState mls = getMusicLockState(key);
199             if (mls != null) {
200                 if (mls.getLockStatus().equals(LockStatus.LOCKED)) {
201                     logger.info(EELFLoggerDelegate.applicationLogger,"The current lock holder for " + key + " is " + mls.getLockHolder()
202                                     + ". Checking if it has exceeded lease");
203                     long currentLockPeriod = System.currentTimeMillis() - mls.getLeaseStartTime();
204                     long currentLeasePeriod = mls.getLeasePeriod();
205                     if (currentLockPeriod > currentLeasePeriod) {
206                         logger.info(EELFLoggerDelegate.applicationLogger,"Lock period " + currentLockPeriod
207                                         + " has exceeded lease period " + currentLeasePeriod);
208                         boolean voluntaryRelease = false;
209                         String currentLockHolder = mls.getLockHolder();
210                         mls = releaseLock(currentLockHolder, voluntaryRelease);
211                     }
212                 }
213             } else
214                 logger.error(EELFLoggerDelegate.errorLogger,key, AppMessages.INVALIDLOCK,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
215           
216             /*
217              * call the traditional acquire lock now and if the result returned is true, set the
218              * begin time-stamp and lease period
219              */
220             if (acquireLock(key, lockId).getResult() == ResultType.SUCCESS) {
221                 mls = getMusicLockState(key);// get latest state
222                 if ( mls == null ) {
223                     logger.info(EELFLoggerDelegate.applicationLogger,"Music Lock State is null");
224                     return new ReturnType(ResultType.FAILURE, "Could not acquire lock, Lock State is null");                    
225                 }
226                 if (mls.getLeaseStartTime() == -1) {// set it again only if it is not set already
227                     mls.setLeaseStartTime(System.currentTimeMillis());
228                     mls.setLeasePeriod(leasePeriod);
229                     getLockingServiceHandle().setLockState(key, mls);
230                 }
231                 long end = System.currentTimeMillis();
232                 logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to acquire leased lock:" + (end - start) + " ms");
233                 return new ReturnType(ResultType.SUCCESS, "Accquired lock");
234             } else {
235                 long end = System.currentTimeMillis();
236                 logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to fail to acquire leased lock:" + (end - start) + " ms");
237                 return new ReturnType(ResultType.FAILURE, "Could not acquire lock");
238             }
239         } catch (Exception e) {
240             StringWriter sw = new StringWriter();
241                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), "[ERR506E] Failed to aquire lock ",ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
242             
243             String exceptionAsString = sw.toString();
244             return new ReturnType(ResultType.FAILURE,
245                             "Exception thrown in acquireLockWithLease:\n" + exceptionAsString);
246         }
247     }
248
249     public static ReturnType acquireLock(String key, String lockId) throws MusicLockingException {
250         /*
251          * first check if I am on top. Since ids are not reusable there is no need to check
252          * lockStatus If the status is unlocked, then the above call will automatically return
253          * false.
254          */
255         Boolean result = false;
256         try {
257             result = getLockingServiceHandle().isMyTurn(lockId);
258         } catch (MusicLockingException e2) {
259             logger.error(EELFLoggerDelegate.errorLogger,AppMessages.INVALIDLOCK + lockId + " " + e2);
260             throw new MusicLockingException();
261         }
262         if (!result) {
263             logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: Not your turn, someone else has the lock");
264             try {
265                                 if (!getLockingServiceHandle().lockIdExists(lockId)) {
266                                         logger.info(EELFLoggerDelegate.applicationLogger, "In acquire lock: this lockId doesn't exist");
267                                         return new ReturnType(ResultType.FAILURE, "Lockid doesn't exist");
268                                 }
269                         } catch (MusicLockingException e) {
270                                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.INVALIDLOCK+lockId,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
271                                  throw new MusicLockingException();
272                         }
273             logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: returning failure");
274             return new ReturnType(ResultType.FAILURE, "Not your turn, someone else has the lock");
275         }
276
277
278         // this is for backward compatibility where locks could also be acquired on just
279         // keyspaces or tables.
280         if (isTableOrKeySpaceLock(key)) {
281             logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: A table or keyspace lock so no need to perform sync...so returning true");
282             return new ReturnType(ResultType.SUCCESS, "A table or keyspace lock so no need to perform sync...so returning true");
283         }
284
285         // read the lock name corresponding to the key and if the status is locked or being locked,
286         // then return false
287         MusicLockState currentMls = null;
288         MusicLockState newMls = null;
289         try {
290             currentMls = getMusicLockState(key);
291             String currentLockHolder = currentMls.getLockHolder();
292             if (lockId.equals(currentLockHolder)) {
293                 logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: You already have the lock!");
294                 return new ReturnType(ResultType.SUCCESS, "You already have the lock!");
295             }
296         } catch (NullPointerException e) {
297                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.INVALIDLOCK+lockId,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
298         }
299
300         // change status to "being locked". This state transition is necessary to ensure syncing
301         // before granting the lock
302         String lockHolder = null;
303         boolean needToSyncQuorum = false;
304         if (currentMls != null)
305             needToSyncQuorum = currentMls.isNeedToSyncQuorum();
306
307
308         newMls = new MusicLockState(MusicLockState.LockStatus.BEING_LOCKED, lockHolder,
309                         needToSyncQuorum);
310         try {
311             getLockingServiceHandle().setLockState(key, newMls);
312         } catch (MusicLockingException e1) {
313                 logger.error(EELFLoggerDelegate.errorLogger,e1.getMessage(), AppMessages.LOCKSTATE+key,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
314         }
315         logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: Set lock state to being_locked");
316
317         // do syncing if this was a forced lock release
318         if (needToSyncQuorum) {
319             logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: Since there was a forcible release, need to sync quorum!");
320             try {
321               syncQuorum(key);
322             } catch (Exception e) {
323               logger.error(EELFLoggerDelegate.errorLogger,"Failed to set Lock state " + e);
324             }
325         }
326
327         // change status to locked
328         lockHolder = lockId;
329         needToSyncQuorum = false;
330         newMls = new MusicLockState(MusicLockState.LockStatus.LOCKED, lockHolder, needToSyncQuorum);
331         try {
332             getLockingServiceHandle().setLockState(key, newMls);
333         } catch (MusicLockingException e) {
334                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.LOCKSTATE+key,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
335         }
336         logger.info(EELFLoggerDelegate.applicationLogger,"In acquire lock: Set lock state to locked and assigned current lock ref "
337                         + lockId + " as holder");
338         
339         return new ReturnType(result?ResultType.SUCCESS:ResultType.FAILURE, "Set lock state to locked and assigned a lock holder");
340     }
341
342
343
344     /**
345      * 
346      * @param keyspaceName
347      * @param kspObject
348      * @return
349      * @throws Exception
350      */
351     public boolean createKeyspace(String keyspaceName, JsonKeySpace kspObject) throws Exception {
352         return true;
353     }
354
355
356     private static void syncQuorum(String key) throws Exception {
357         logger.info(EELFLoggerDelegate.applicationLogger,"Performing sync operation---");
358         String[] splitString = key.split("\\.");
359         String keyspaceName = splitString[0];
360         String tableName = splitString[1];
361         String primaryKeyValue = splitString[2];
362         PreparedQueryObject selectQuery = new PreparedQueryObject();
363         PreparedQueryObject updateQuery = new PreparedQueryObject();
364
365         // get the primary key d
366         TableMetadata tableInfo = returnColumnMetadata(keyspaceName, tableName);
367         String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();// we only support single
368                                                                            // primary key
369         DataType primaryKeyType = tableInfo.getPrimaryKey().get(0).getType();
370         Object cqlFormattedPrimaryKeyValue =
371                         MusicUtil.convertToActualDataType(primaryKeyType, primaryKeyValue);
372
373         // get the row of data from a quorum
374         selectQuery.appendQueryString("SELECT *  FROM " + keyspaceName + "." + tableName + " WHERE "
375                         + primaryKeyName + "= ?" + ";");
376         selectQuery.addValue(cqlFormattedPrimaryKeyValue);
377         ResultSet results = null;
378         try {
379             results = getDSHandle().executeCriticalGet(selectQuery);
380             // write it back to a quorum
381             Row row = results.one();
382             ColumnDefinitions colInfo = row.getColumnDefinitions();
383             int totalColumns = colInfo.size();
384             int counter = 1;
385             StringBuilder fieldValueString = new StringBuilder("");
386             for (Definition definition : colInfo) {
387                 String colName = definition.getName();
388                 if (colName.equals(primaryKeyName))
389                     continue;
390                 DataType colType = definition.getType();
391                 Object valueObj = getDSHandle().getColValue(row, colName, colType);
392                 Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
393                 fieldValueString.append(colName + " = ?");
394                 updateQuery.addValue(valueString);
395                 if (counter != (totalColumns - 1))
396                     fieldValueString.append(",");
397                 counter = counter + 1;
398             }
399             updateQuery.appendQueryString("UPDATE " + keyspaceName + "." + tableName + " SET "
400                             + fieldValueString + " WHERE " + primaryKeyName + "= ? " + ";");
401             updateQuery.addValue(cqlFormattedPrimaryKeyValue);
402
403             getDSHandle().executePut(updateQuery, "critical");
404         } catch (MusicServiceException | MusicQueryException e) {
405                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.QUERYERROR +""+updateQuery ,ErrorSeverity.MAJOR, ErrorTypes.QUERYERROR);
406         }
407     }
408
409
410
411
412     /**
413      * 
414      * @param query
415      * @return ResultSet
416      */
417     public static ResultSet quorumGet(PreparedQueryObject query) {
418         ResultSet results = null;
419         try {
420             results = getDSHandle().executeCriticalGet(query);
421         } catch (MusicServiceException | MusicQueryException e) {
422                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.MAJOR, ErrorTypes.GENERALSERVICEERROR);
423         
424         }
425         return results;
426
427     }
428
429     /**
430      * 
431      * @param results
432      * @return
433      * @throws MusicServiceException 
434      */
435     public static Map<String, HashMap<String, Object>> marshallResults(ResultSet results) throws MusicServiceException {
436         return getDSHandle().marshalData(results);
437     }
438
439     /**
440      * 
441      * @param lockName
442      * @return
443      */
444     public static String whoseTurnIsIt(String lockName) {
445
446         try {
447             return getLockingServiceHandle().whoseTurnIsIt("/" + lockName) + "";
448         } catch (MusicLockingException e) {
449                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.LOCKINGERROR+lockName ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
450         }
451         return null;
452
453
454     }
455
456     /**
457      * 
458      * @param lockId
459      * @return
460      */
461     public static String getLockNameFromId(String lockId) {
462         StringTokenizer st = new StringTokenizer(lockId);
463         return st.nextToken("$");
464     }
465
466     public static void destroyLockRef(String lockId) {
467         long start = System.currentTimeMillis();
468         try {
469             getLockingServiceHandle().unlockAndDeleteId(lockId);
470         } catch (MusicLockingException | NoNodeException e) {
471                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.DESTROYLOCK+lockId  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
472         } 
473         long end = System.currentTimeMillis();
474         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to destroy lock reference:" + (end - start) + " ms");
475     }
476
477     public static MusicLockState releaseLock(String lockId, boolean voluntaryRelease) {
478         long start = System.currentTimeMillis();
479         try {
480             getLockingServiceHandle().unlockAndDeleteId(lockId);
481         } catch (MusicLockingException e1) {
482                 logger.error(EELFLoggerDelegate.errorLogger,e1.getMessage(), AppMessages.RELEASELOCK+lockId  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
483         } catch (KeeperException.NoNodeException nne) {
484                         logger.error(EELFLoggerDelegate.errorLogger,"Failed to release Lock " + lockId + " " + nne);
485                         MusicLockState mls = new MusicLockState("Lock doesn't exists. Release lock operation failed.");
486                         return mls;
487         }
488         String lockName = getLockNameFromId(lockId);
489         MusicLockState mls;
490         String lockHolder = null;
491         if (voluntaryRelease) {
492             mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder);
493             logger.info(EELFLoggerDelegate.applicationLogger,"In unlock: lock voluntarily released for " + lockId);
494         } else {
495             boolean needToSyncQuorum = true;
496             mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder,
497                             needToSyncQuorum);
498             logger.info(EELFLoggerDelegate.applicationLogger,"In unlock: lock forcibly released for " + lockId);
499         }
500         try {
501             getLockingServiceHandle().setLockState(lockName, mls);
502         } catch (MusicLockingException e) {
503                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.RELEASELOCK+lockId  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
504         }
505         long end = System.currentTimeMillis();
506         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to release lock:" + (end - start) + " ms");
507         return mls;
508     }
509     
510     public static  void  voluntaryReleaseLock(String lockId) throws MusicLockingException{
511                 try {
512                         getLockingServiceHandle().unlockAndDeleteId(lockId);
513                 } catch (KeeperException.NoNodeException e) {
514                         // ??? No way
515                 }
516         }
517
518     /**
519      * 
520      * @param lockName
521      * @throws MusicLockingException 
522      */
523     public static void deleteLock(String lockName) throws MusicLockingException {
524         long start = System.currentTimeMillis();
525         logger.info(EELFLoggerDelegate.applicationLogger,"Deleting lock for " + lockName);
526         try {
527             getLockingServiceHandle().deleteLock("/" + lockName);
528         } catch (MusicLockingException e) {
529                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.DELTELOCK+lockName  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
530                 throw new MusicLockingException(e.getMessage());
531         }
532         long end = System.currentTimeMillis();
533         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to delete lock:" + (end - start) + " ms");
534     }
535
536
537
538     /**
539      * 
540      * @param keyspace
541      * @param tablename
542      * @return
543      * @throws MusicServiceException 
544      */
545     public static TableMetadata returnColumnMetadata(String keyspace, String tablename) throws MusicServiceException {
546         return getDSHandle().returnColumnMetadata(keyspace, tablename);
547     }
548
549
550     /**
551      * 
552      * @param nodeName
553      */
554     public static void pureZkCreate(String nodeName) {
555         try {
556             getLockingServiceHandle().getzkLockHandle().createNode(nodeName);
557         } catch (MusicLockingException e) {
558                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), "[ERR512E] Failed to get ZK Lock Handle "  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
559         }
560     }
561
562     /**
563      * 
564      * @param nodeName
565      * @param data
566      */
567     public static void pureZkWrite(String nodeName, byte[] data) {
568         long start = System.currentTimeMillis();
569         logger.info(EELFLoggerDelegate.applicationLogger,"Performing zookeeper write to " + nodeName);
570         try {
571             getLockingServiceHandle().getzkLockHandle().setNodeData(nodeName, data);
572         } catch (MusicLockingException e) {
573                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), "[ERR512E] Failed to get ZK Lock Handle "  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
574         }
575         logger.info(EELFLoggerDelegate.applicationLogger,"Performed zookeeper write to " + nodeName);
576         long end = System.currentTimeMillis();
577         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken for the actual zk put:" + (end - start) + " ms");
578     }
579
580     /**
581      * 
582      * @param nodeName
583      * @return
584      */
585     public static byte[] pureZkRead(String nodeName) {
586         long start = System.currentTimeMillis();
587         byte[] data = null;
588         try {
589             data = getLockingServiceHandle().getzkLockHandle().getNodeData(nodeName);
590         } catch (MusicLockingException e) {
591                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), "[ERR512E] Failed to get ZK Lock Handle "  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
592         }
593         long end = System.currentTimeMillis();
594         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken for the actual zk put:" + (end - start) + " ms");
595         return data;
596     }
597
598
599
600     // Prepared Query Additions.
601
602     /**
603      * 
604      * @param keyspaceName
605      * @param tableName
606      * @param primaryKey
607      * @param queryObject
608      * @return ReturnType
609      * @throws MusicServiceException
610      */
611     public static ReturnType eventualPut(PreparedQueryObject queryObject) {
612         boolean result = false;
613         try {
614             result = getDSHandle().executePut(queryObject, MusicUtil.EVENTUAL);
615         } catch (MusicServiceException | MusicQueryException ex) {
616                 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), "[ERR512E] Failed to get ZK Lock Handle "  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
617             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() + "  " + ex.getCause() + " " + ex);
618             return new ReturnType(ResultType.FAILURE, ex.getMessage());
619         }
620         if (result) {
621             return new ReturnType(ResultType.SUCCESS, "Success");
622         } else {
623             return new ReturnType(ResultType.FAILURE, "Failure");
624         }
625     }
626
627     /**
628      * 
629      * @param keyspaceName
630      * @param tableName
631      * @param primaryKey
632      * @param queryObject
633      * @param lockId
634      * @return
635      */
636     public static ReturnType criticalPut(String keyspaceName, String tableName, String primaryKey,
637                     PreparedQueryObject queryObject, String lockId, Condition conditionInfo) {
638         long start = System.currentTimeMillis();
639
640         try {
641             MusicLockState mls = getLockingServiceHandle()
642                             .getLockState(keyspaceName + "." + tableName + "." + primaryKey);
643             if (mls.getLockHolder().equals(lockId) == true) {
644                 if (conditionInfo != null)
645                   try {
646                     if (conditionInfo.testCondition() == false)
647                         return new ReturnType(ResultType.FAILURE,
648                                         "Lock acquired but the condition is not true");
649                   } catch (Exception e) {
650                     return new ReturnType(ResultType.FAILURE,
651                             "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n"
652                                             + e.getMessage());
653                   }
654                 getDSHandle().executePut(queryObject, MusicUtil.CRITICAL);
655                 long end = System.currentTimeMillis();
656                 logger.info(EELFLoggerDelegate.applicationLogger,"Time taken for the critical put:" + (end - start) + " ms");
657                 return new ReturnType(ResultType.SUCCESS, "Update performed");
658             } else
659                 return new ReturnType(ResultType.FAILURE,
660                                 "Cannot perform operation since you are the not the lock holder");
661         } catch (MusicQueryException | MusicServiceException  e) {
662             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage());
663             return new ReturnType(ResultType.FAILURE,
664                             "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n"
665                                             + e.getMessage());
666         }catch(MusicLockingException ex){
667             return new ReturnType(ResultType.FAILURE,ex.getMessage());
668         }
669
670     }
671
672     /**
673      * 
674      * @param queryObject
675      * @param consistency
676      * @return Boolean Indicates success or failure
677      * @throws MusicServiceException 
678      * 
679      * 
680      */
681     public static ResultType nonKeyRelatedPut(PreparedQueryObject queryObject, String consistency) throws MusicServiceException {
682         // this is mainly for some functions like keyspace creation etc which does not
683         // really need the bells and whistles of Music locking.
684         boolean result = false;
685         try {
686             result = getDSHandle().executePut(queryObject, consistency);
687         } catch (MusicQueryException | MusicServiceException ex) {
688                 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
689             throw new MusicServiceException(ex.getMessage());
690         }
691         return result?ResultType.SUCCESS:ResultType.FAILURE;
692     }
693
694     /**
695      * This method performs DDL operation on cassandra.
696      * 
697      * @param queryObject query object containing prepared query and values
698      * @return ResultSet
699      * @throws MusicServiceException 
700      */
701     public static ResultSet get(PreparedQueryObject queryObject) throws MusicServiceException {
702         ResultSet results = null;
703         try {
704                         results = getDSHandle().executeEventualGet(queryObject);
705         } catch (MusicQueryException | MusicServiceException e) {
706             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage());
707             throw new MusicServiceException(e.getMessage());
708         }
709         return results;
710     }
711
712     /**
713      * This method performs DDL operations on cassandra, if the the resource is available. Lock ID
714      * is used to check if the resource is free.
715      * 
716      * @param keyspaceName name of the keyspace
717      * @param tableName name of the table
718      * @param primaryKey primary key value
719      * @param queryObject query object containing prepared query and values
720      * @param lockId lock ID to check if the resource is free to perform the operation.
721      * @return ResultSet
722      */
723     public static ResultSet criticalGet(String keyspaceName, String tableName, String primaryKey,
724                     PreparedQueryObject queryObject, String lockId) throws MusicServiceException {
725         ResultSet results = null;
726         try {
727             MusicLockState mls = getLockingServiceHandle()
728                             .getLockState(keyspaceName + "." + tableName + "." + primaryKey);
729             if (mls.getLockHolder().equals(lockId)) {
730                 results = getDSHandle().executeCriticalGet(queryObject);
731             } else
732                 throw new MusicServiceException("YOU DO NOT HAVE THE LOCK");
733         } catch (MusicQueryException | MusicServiceException | MusicLockingException e) {
734                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
735         }
736         return results;
737     }
738
739     /**
740      * This method performs DML operation on cassandra, when the lock of the dd is acquired.
741      * 
742      * @param keyspaceName name of the keyspace
743      * @param tableName name of the table
744      * @param primaryKey primary key value
745      * @param queryObject query object containing prepared query and values
746      * @return ReturnType
747      * @throws MusicLockingException 
748      */
749     public static ReturnType atomicPut(String keyspaceName, String tableName, String primaryKey,
750                     PreparedQueryObject queryObject, Condition conditionInfo) throws MusicLockingException {
751
752         long start = System.currentTimeMillis();
753         String key = keyspaceName + "." + tableName + "." + primaryKey;
754         String lockId = createLockReference(key);
755         long lockCreationTime = System.currentTimeMillis();
756         ReturnType lockAcqResult = acquireLock(key, lockId);
757         long lockAcqTime = System.currentTimeMillis();
758         if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
759             logger.info(EELFLoggerDelegate.applicationLogger,"acquired lock with id " + lockId);
760             ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey,
761                             queryObject, lockId, conditionInfo);
762             long criticalPutTime = System.currentTimeMillis();
763             voluntaryReleaseLock(lockId);
764             long lockDeleteTime = System.currentTimeMillis();
765             String timingInfo = "|lock creation time:" + (lockCreationTime - start)
766                             + "|lock accquire time:" + (lockAcqTime - lockCreationTime)
767                             + "|critical put time:" + (criticalPutTime - lockAcqTime)
768                             + "|lock delete time:" + (lockDeleteTime - criticalPutTime) + "|";
769             criticalPutResult.setTimingInfo(timingInfo);
770             return criticalPutResult;
771         } else {
772             logger.info(EELFLoggerDelegate.applicationLogger,"unable to acquire lock, id " + lockId);
773             destroyLockRef(lockId);
774             return lockAcqResult;
775         }
776     }
777     
778     /**
779      * this function is mainly for the benchmarks to see the effect of lock deletion.
780      * 
781      * @param keyspaceName
782      * @param tableName
783      * @param primaryKey
784      * @param queryObject
785      * @param conditionInfo
786      * @return
787      * @throws MusicLockingException 
788      */
789     public static ReturnType atomicPutWithDeleteLock(String keyspaceName, String tableName,
790                     String primaryKey, PreparedQueryObject queryObject, Condition conditionInfo) throws MusicLockingException {
791
792         long start = System.currentTimeMillis();
793         String key = keyspaceName + "." + tableName + "." + primaryKey;
794         String lockId = createLockReference(key);
795         long lockCreationTime = System.currentTimeMillis();
796         long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
797         ReturnType lockAcqResult = acquireLock(key, lockId);
798         long lockAcqTime = System.currentTimeMillis();
799         if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
800             logger.info(EELFLoggerDelegate.applicationLogger,"acquired lock with id " + lockId);
801             ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey,
802                             queryObject, lockId, conditionInfo);
803             long criticalPutTime = System.currentTimeMillis();
804             deleteLock(key);
805             long lockDeleteTime = System.currentTimeMillis();
806             String timingInfo = "|lock creation time:" + (lockCreationTime - start)
807                             + "|lock accquire time:" + (lockAcqTime - lockCreationTime)
808                             + "|critical put time:" + (criticalPutTime - lockAcqTime)
809                             + "|lock delete time:" + (lockDeleteTime - criticalPutTime) + "|";
810             criticalPutResult.setTimingInfo(timingInfo);
811             return criticalPutResult;
812         } else {
813             logger.info(EELFLoggerDelegate.applicationLogger,"unable to acquire lock, id " + lockId);
814             deleteLock(key);
815             return lockAcqResult;
816         }
817     }
818     
819
820
821
822     /**
823      * This method performs DDL operation on cassasndra, when the lock for the resource is acquired.
824      * 
825      * @param keyspaceName name of the keyspace
826      * @param tableName name of the table
827      * @param primaryKey primary key value
828      * @param queryObject query object containing prepared query and values
829      * @return ResultSet
830      * @throws MusicServiceException
831      * @throws MusicLockingException 
832      */
833     public static ResultSet atomicGet(String keyspaceName, String tableName, String primaryKey,
834                     PreparedQueryObject queryObject) throws MusicServiceException, MusicLockingException {
835         String key = keyspaceName + "." + tableName + "." + primaryKey;
836         String lockId = createLockReference(key);
837         long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
838         ReturnType lockAcqResult = acquireLock(key, lockId);
839         if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
840             logger.info(EELFLoggerDelegate.applicationLogger,"acquired lock with id " + lockId);
841             ResultSet result =
842                             criticalGet(keyspaceName, tableName, primaryKey, queryObject, lockId);
843             voluntaryReleaseLock(lockId);
844             return result;
845         } else {
846                 destroyLockRef(lockId);
847             logger.info(EELFLoggerDelegate.applicationLogger,"unable to acquire lock, id " + lockId);
848             return null;
849         }
850     }
851     
852         public static ResultSet atomicGetWithDeleteLock(String keyspaceName, String tableName, String primaryKey,
853                         PreparedQueryObject queryObject) throws MusicServiceException, MusicLockingException {
854                 String key = keyspaceName + "." + tableName + "." + primaryKey;
855                 String lockId = createLockReference(key);
856                 long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
857
858                 ReturnType lockAcqResult = acquireLock(key, lockId);
859
860                 if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
861                         logger.info(EELFLoggerDelegate.applicationLogger, "acquired lock with id " + lockId);
862                         ResultSet result = criticalGet(keyspaceName, tableName, primaryKey, queryObject, lockId);
863                         deleteLock(key);
864                         return result;
865                 } else {
866                         deleteLock(key);
867                         logger.info(EELFLoggerDelegate.applicationLogger, "unable to acquire lock, id " + lockId);
868                         return null;
869                 }
870         }
871     
872     
873
874     /**
875      * authenticate user logic
876      * 
877      * @param nameSpace
878      * @param userId
879      * @param password
880      * @param keyspace
881      * @param aid
882      * @param operation
883      * @return
884      * @throws Exception
885      */
886     public static Map<String, Object> autheticateUser(String nameSpace, String userId,
887                     String password, String keyspace, String aid, String operation)
888                     throws Exception {
889         Map<String, Object> resultMap = new HashMap<>();
890         String uuid = null;
891         resultMap = CachingUtil.validateRequest(nameSpace, userId, password, keyspace, aid,
892                         operation);
893         if (!resultMap.isEmpty())
894             return resultMap;
895         String isAAFApp = null;
896         try {
897             isAAFApp= CachingUtil.isAAFApplication(nameSpace);
898         } catch(MusicServiceException e) {
899            resultMap.put("Exception", e.getMessage());
900            return resultMap;
901         }
902         if(isAAFApp == null) {
903             resultMap.put("Exception", "Namespace: "+nameSpace+" doesn't exist. Please make sure ns(appName)"
904                     + " is correct and Application is onboarded.");
905             return resultMap;
906         }
907         boolean isAAF = Boolean.valueOf(isAAFApp);
908         if (userId == null || password == null) {
909                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
910             logger.error(EELFLoggerDelegate.errorLogger,"One or more required headers is missing. userId: " + userId
911                             + " :: password: " + password);
912             resultMap.put("Exception",
913                             "UserId and Password are mandatory for the operation " + operation);
914             return resultMap;
915         }
916         if(!isAAF && !(operation.equals("createKeySpace"))) {
917             resultMap = CachingUtil.authenticateAIDUser(nameSpace, userId, password, keyspace);
918             if (!resultMap.isEmpty())
919                 return resultMap;
920             
921         }
922         if (isAAF && nameSpace != null && userId != null && password != null) {
923             boolean isValid = true;
924             try {
925                  isValid = CachingUtil.authenticateAAFUser(nameSpace, userId, password, keyspace);
926             } catch (Exception e) {
927                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.AUTHENTICATIONERROR  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
928                 logger.error(EELFLoggerDelegate.errorLogger,"Got exception while AAF authentication for namespace " + nameSpace);
929                 resultMap.put("Exception", e.getMessage());
930             }
931             if (!isValid) {
932                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.AUTHENTICATIONERROR  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
933                 resultMap.put("Exception", "User not authenticated...");
934             }
935             if (!resultMap.isEmpty())
936                 return resultMap;
937
938         }
939
940         if (operation.equals("createKeySpace")) {
941             logger.info(EELFLoggerDelegate.applicationLogger,"AID is not provided. Creating new UUID for keyspace.");
942             PreparedQueryObject pQuery = new PreparedQueryObject();
943             pQuery.appendQueryString(
944                             "select uuid from admin.keyspace_master where application_name=? and username=? and keyspace_name=? allow filtering");
945             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), nameSpace));
946             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
947             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
948                             MusicUtil.DEFAULTKEYSPACENAME));
949
950             try {
951                 Row rs = MusicCore.get(pQuery).one();
952                 uuid = rs.getUUID("uuid").toString();
953                 resultMap.put("uuid", "existing");
954             } catch (Exception e) {
955                 logger.info(EELFLoggerDelegate.applicationLogger,"No UUID found in DB. So creating new UUID.");
956                 uuid = CachingUtil.generateUUID();
957                 resultMap.put("uuid", "new");
958             }
959             resultMap.put("aid", uuid);
960         }
961
962         return resultMap;
963     }
964     
965     /**
966      * @param lockName
967      * @return
968      */
969     public static Map<String, Object> validateLock(String lockName) {
970         Map<String, Object> resultMap = new HashMap<>();
971         String[] locks = lockName.split("\\.");
972         if(locks.length < 3) {
973             resultMap.put("Exception", "Invalid lock. Please make sure lock is of the type keyspaceName.tableName.primaryKey");
974             return resultMap;
975         }
976         String keyspace= locks[0];
977         if(keyspace.startsWith("$"))
978             keyspace = keyspace.substring(1);
979         resultMap.put("keyspace",keyspace);
980         return resultMap;
981     }
982 }