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