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