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