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