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