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