2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (c) 2017 AT&T Intellectual Property
6 * ===================================================================
7 * Modifications Copyright (c) 2019 IBM.
8 * Modifications Copyright (c) 2019 Samsung.
9 * ===================================================================
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
22 * ============LICENSE_END=============================================
23 * ====================================================================
26 package org.onap.music.main;
28 import com.datastax.driver.core.ColumnDefinitions;
29 import com.datastax.driver.core.ColumnDefinitions.Definition;
30 import com.datastax.driver.core.ResultSet;
31 import com.datastax.driver.core.Row;
33 import java.io.FileNotFoundException;
34 import java.math.BigInteger;
35 import java.nio.ByteBuffer;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.List;
40 import java.util.Scanner;
42 import java.util.UUID;
44 import javax.ws.rs.core.Response;
45 import javax.ws.rs.core.Response.ResponseBuilder;
46 import org.onap.music.datastore.MusicDataStoreHandle;
47 import org.onap.music.datastore.PreparedQueryObject;
48 import org.onap.music.eelf.logging.EELFLoggerDelegate;
49 import org.onap.music.eelf.logging.format.AppMessages;
50 import org.onap.music.eelf.logging.format.ErrorSeverity;
51 import org.onap.music.eelf.logging.format.ErrorTypes;
52 import org.onap.music.exceptions.MusicQueryException;
53 import org.onap.music.exceptions.MusicServiceException;
54 import org.onap.music.service.MusicCoreService;
55 import org.onap.music.service.impl.MusicCassaCore;
57 import com.datastax.driver.core.ConsistencyLevel;
58 import com.datastax.driver.core.DataType;
63 * Properties This will take Properties and load them into MusicUtil.
64 * This is a hack for now. Eventually it would bebest to do this in
68 public class MusicUtil {
69 private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicUtil.class);
71 // Consistancy Constants
72 public static final String ATOMIC = "atomic";
73 public static final String EVENTUAL = "eventual";
74 public static final String CRITICAL = "critical";
75 public static final String EVENTUAL_NB = "eventual_nb";
76 public static final String ALL = "all";
77 public static final String QUORUM = "quorum";
78 public static final String LOCAL_QUORUM = "local_quorum";
79 public static final String ONE = "one";
80 public static final String ATOMICDELETELOCK = "atomic_delete_lock";
83 private static final String XLATESTVERSION = "X-latestVersion";
84 private static final String XMINORVERSION = "X-minorVersion";
85 private static final String XPATCHVERSION = "X-patchVersion";
86 public static final String AUTHORIZATION = "Authorization";
89 public static final String SELECT = "select";
90 public static final String INSERT = "insert";
91 public static final String UPDATE = "update";
92 public static final String UPSERT = "upsert";
93 public static final String USERID = "userId";
94 public static final String PASSWORD = "";
95 public static final String CASSANDRA = "cassandra";
97 private static final String LOCALHOST = "localhost";
98 private static final String PROPERTIES_FILE = "/opt/app/music/etc/music.properties";
99 public static final String DEFAULTKEYSPACENAME = "TBD";
101 private static long defaultLockLeasePeriod = 6000;
102 // Amount of times to retry to delete a lock in atomic.
103 private static int retryCount = 3;
104 private static String lockUsing = MusicUtil.CASSANDRA;
106 private static boolean isCadi = false;
107 // Keyspace Creation on/off
108 private static boolean isKeyspaceActive = false;
109 private static boolean debug = true;
110 private static String version = "0.0.0";
111 private static String build = "";
112 private static long lockDaemonSleepms = 1000;
113 private static Set<String> keyspacesToCleanLocks = new HashSet<>();
115 private static String musicPropertiesFilePath = PROPERTIES_FILE;
116 // private static final String[] propKeys = new String[] { MusicUtil.class.getDeclaredMethod(arg0, )"build","cassandra.host", "debug",
117 // "version", "music.properties", "lock.lease.period", "cassandra.user",
118 // "cassandra.password", "aaf.endpoint.url","admin.username","admin.password",
119 // "music.namespace","admin.aaf.role","cassandra.port","lock.using","retry.count",
120 // "transId.header.required","conversation.header.required","clientId.header.required",
121 // "messageId.header.required","transId.header.prefix","conversation.header.prefix",
122 // "clientId.header.prefix","messageId.header.prefix"};
123 // Consistency Constants and variables.
124 private static final String[] cosistencyLevel = new String[] {
125 "ALL","EACH_QUORUM","QUORUM","LOCAL_QUORUM","ONE","TWO",
126 "THREE","LOCAL_ONE","ANY","SERIAL","LOCAL_SERIAL"};
127 private static final Map<String,ConsistencyLevel> consistencyName = new HashMap<>();
129 consistencyName.put("ONE",ConsistencyLevel.ONE);
130 consistencyName.put("TWO",ConsistencyLevel.TWO);
131 consistencyName.put("THREE",ConsistencyLevel.THREE);
132 consistencyName.put("SERIAL",ConsistencyLevel.SERIAL);
133 consistencyName.put("ALL",ConsistencyLevel.ALL);
134 consistencyName.put("EACH_QUORUM",ConsistencyLevel.EACH_QUORUM);
135 consistencyName.put("QUORUM",ConsistencyLevel.QUORUM);
136 consistencyName.put("LOCAL_QUORUM",ConsistencyLevel.LOCAL_QUORUM);
137 consistencyName.put("LOCAL_ONE",ConsistencyLevel.LOCAL_ONE);
138 consistencyName.put("LOCAL_SERIAL",ConsistencyLevel.LOCAL_SERIAL);
142 private static String cassName = "cassandra";
143 private static String cassPwd;
144 private static String myCassaHost = LOCALHOST;
145 private static int cassandraPort = 9042;
146 private static int cassandraConnectTimeOutMS;
147 private static int cassandraReadTimeOutMS;
150 private static String musicAafNs = "org.onap.music.cadi";
153 public static final long MusicEternityEpochMillis = 1533081600000L; // Wednesday, August 1, 2018 12:00:00 AM
154 public static final long MaxLockReferenceTimePart = 1000000000000L; // millis after eternity (eq sometime in 2050)
155 public static final long MaxCriticalSectionDurationMillis = 1L * 24 * 60 * 60 * 1000; // 1 day
157 // Response/Request tracking headers
158 private static String transIdPrefix = "false";
159 private static String conversationIdPrefix = "false";
160 private static String clientIdPrefix = "false";
161 private static String messageIdPrefix = "false";
162 private static Boolean transIdRequired = false;
163 private static Boolean conversationIdRequired = false;
164 private static Boolean clientIdRequired = false;
165 private static Boolean messageIdRequired = false;
166 private static String cipherEncKey = "";
168 private static long createLockWaitPeriod = 300;
169 private static int createLockWaitIncrement = 50;
171 public static long getCreateLockWaitPeriod() {
172 return createLockWaitPeriod;
175 public static void setCreateLockWaitPeriod(long createLockWaitPeriod) {
176 MusicUtil.createLockWaitPeriod = createLockWaitPeriod;
179 public static int getCreateLockWaitIncrement() {
180 return createLockWaitIncrement;
183 public static void setCreateLockWaitIncrement(int createLockWaitIncrement) {
184 MusicUtil.createLockWaitIncrement = createLockWaitIncrement;
188 throw new IllegalStateException("Utility Class");
191 public static String getLockUsing() {
195 public static void setLockUsing(String lockUsing) {
196 MusicUtil.lockUsing = lockUsing;
201 * @return cassandra port
203 public static int getCassandraPort() {
204 return cassandraPort;
209 * @param cassandraPort
211 public static void setCassandraPort(int cassandraPort) {
212 MusicUtil.cassandraPort = cassandraPort;
215 * @return the cassName
217 public static String getCassName() {
222 * @return the cassPwd
224 public static String getCassPwd() {
228 public static int getCassandraConnectTimeOutMS() {
229 return cassandraConnectTimeOutMS;
232 public static void setCassandraConnectTimeOutMS(int cassandraConnectTimeOutMS) {
233 MusicUtil.cassandraConnectTimeOutMS = cassandraConnectTimeOutMS;
236 public static int getCassandraReadTimeOutMS() {
237 return cassandraReadTimeOutMS;
240 public static void setCassandraReadTimeOutMS(int cassandraReadTimeOutMS) {
241 MusicUtil.cassandraReadTimeOutMS = cassandraReadTimeOutMS;
245 * Returns An array of property names that should be in the Properties
250 // public static String[] getPropkeys() {
251 // return propKeys.clone();
255 * Get MusicPropertiesFilePath - Default = /opt/music/music.properties
256 * property file value - music.properties
260 public static String getMusicPropertiesFilePath() {
261 return musicPropertiesFilePath;
265 * Set MusicPropertiesFilePath
267 * @param musicPropertiesFilePath
269 public static void setMusicPropertiesFilePath(String musicPropertiesFilePath) {
270 MusicUtil.musicPropertiesFilePath = musicPropertiesFilePath;
274 * Get DefaultLockLeasePeriod - Default = 6000 property file value -
279 public static long getDefaultLockLeasePeriod() {
280 return defaultLockLeasePeriod;
284 * Set DefaultLockLeasePeriod
286 * @param defaultLockLeasePeriod
288 public static void setDefaultLockLeasePeriod(long defaultLockLeasePeriod) {
289 MusicUtil.defaultLockLeasePeriod = defaultLockLeasePeriod;
297 public static void setDebug(boolean debug) {
298 MusicUtil.debug = debug;
302 * Is Debug - Default = true property file value - debug
306 public static boolean isDebug() {
315 public static void setVersion(String version) {
316 MusicUtil.version = version;
320 * Return the version property file value - version.
324 public static String getVersion() {
329 * Set the build of project which is a combination of the
330 * version and the date.
332 * @param build - version-date.
334 public static void setBuild(String build) {
335 MusicUtil.build = build;
339 * Return the build version-date.
341 public static String getBuild() {
346 * Get MyCassHost - Cassandra Hostname - Default = localhost property file
347 * value - cassandra.host
351 public static String getMyCassaHost() {
356 * Set MyCassHost - Cassandra Hostname
358 * @param myCassaHost .
360 public static void setMyCassaHost(String myCassaHost) {
361 MusicUtil.myCassaHost = myCassaHost;
365 * Gey default retry count
368 public static int getRetryCount() {
374 * @param retryCount .
376 public static void setRetryCount(int retryCount) {
377 MusicUtil.retryCount = retryCount;
382 * This is used to turn keyspace creation api on/off.
385 public static void setKeyspaceActive(Boolean keyspaceActive) {
386 MusicUtil.isKeyspaceActive = keyspaceActive;
390 * This is used to turn keyspace creation api on/off.
391 * @return boolean isKeyspaceActive
393 public static boolean isKeyspaceActive() {
394 return isKeyspaceActive;
398 * This method depricated as its not used or needed.
403 public static String getTestType() {
404 String testType = "";
406 Scanner fileScanner = new Scanner(new File(""));
407 testType = fileScanner.next();// ignore the my id line
408 @SuppressWarnings("unused")
409 String batchSize = fileScanner.next();// ignore the my public ip line
411 } catch (FileNotFoundException e) {
412 logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e);
419 * Method to do a Thread Sleep.
420 * Used for adding a delay.
424 public static void sleep(long time) {
427 } catch (InterruptedException e) {
428 logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e);
429 Thread.currentThread().interrupt();
434 * Utility function to check if the query object is valid.
440 public static boolean isValidQueryObject(boolean withparams, PreparedQueryObject queryObject) {
442 int noOfValues = queryObject.getValues().size();
444 char[] temp = queryObject.getQuery().toCharArray();
445 for (int i = 0; i < temp.length; i++) {
449 return (noOfValues == noOfParams);
451 return !queryObject.getQuery().isEmpty();
456 public static void setCassName(String cassName) {
457 MusicUtil.cassName = cassName;
460 public static void setCassPwd(String cassPwd) {
461 MusicUtil.cassPwd = cassPwd;
464 @SuppressWarnings("unchecked")
465 public static String convertToCQLDataType(DataType type, Object valueObj) throws Exception {
468 switch (type.getName()) {
470 value = valueObj + "";
474 String valueString = valueObj + "";
475 valueString = valueString.replace("'", "''");
476 value = "'" + valueString + "'";
479 Map<String, Object> otMap = (Map<String, Object>) valueObj;
480 value = "{" + jsonMaptoSqlString(otMap, ",") + "}";
484 value = valueObj + "";
495 * @throws MusicTypeConversionException
498 @SuppressWarnings("unchecked")
499 public static Object convertToActualDataType(DataType colType, Object valueObj) throws Exception {
500 String valueObjString = valueObj + "";
501 switch (colType.getName()) {
503 return UUID.fromString(valueObjString);
505 return BigInteger.valueOf(Long.parseLong(valueObjString));
507 return Long.parseLong(valueObjString);
509 return Integer.parseInt(valueObjString);
511 return Float.parseFloat(valueObjString);
513 return Double.parseDouble(valueObjString);
515 return Boolean.parseBoolean(valueObjString);
517 return (Map<String, Object>) valueObj;
519 return (List<Object>)valueObj;
523 return valueObjString;
527 public static ByteBuffer convertToActualDataType(DataType colType, byte[] valueObj) {
528 ByteBuffer buffer = ByteBuffer.wrap(valueObj);
534 * Utility function to parse json map into sql like string
537 * @param lineDelimiter
541 public static String jsonMaptoSqlString(Map<String, Object> jMap, String lineDelimiter) throws Exception{
542 StringBuilder sqlString = new StringBuilder();
544 for (Map.Entry<String, Object> entry : jMap.entrySet()) {
545 Object ot = entry.getValue();
546 String value = ot + "";
547 if (ot instanceof String) {
548 value = "'" + value.replace("'", "''") + "'";
550 sqlString.append("'" + entry.getKey() + "':" + value);
551 if (counter != jMap.size() - 1)
552 sqlString.append(lineDelimiter);
553 counter = counter + 1;
555 return sqlString.toString();
558 @SuppressWarnings("unused")
559 public static String buildVersion(String major, String minor, String patch) {
561 major += "." + minor;
563 major += "." + patch;
570 * Currently this will build a header with X-latestVersion, X-minorVersion and X-pathcVersion
571 * X-latestVerstion will be equal to the latest full version.
572 * X-minorVersion - will be equal to the latest minor version.
573 * X-pathVersion - will be equal to the latest patch version.
574 * Future plans will change this.
581 public static ResponseBuilder buildVersionResponse(String major, String minor, String patch) {
582 ResponseBuilder response = Response.noContent();
583 String versionIn = buildVersion(major,minor,patch);
584 String version = MusicUtil.getVersion();
585 String[] verArray = version.split("\\.",3);
586 if ( minor != null ) {
587 response.header(XMINORVERSION,minor);
589 response.header(XMINORVERSION,verArray[1]);
591 if ( patch != null ) {
592 response.header(XPATCHVERSION,patch);
594 response.header(XPATCHVERSION,verArray[2]);
596 response.header(XLATESTVERSION,version);
597 logger.info(EELFLoggerDelegate.auditLogger,"Version In:" + versionIn);
601 public static boolean isValidConsistency(String consistency) {
602 for (String string : cosistencyLevel) {
603 if (string.equalsIgnoreCase(consistency))
610 public static ConsistencyLevel getConsistencyLevel(String consistency) {
611 return consistencyName.get(consistency.toUpperCase());
615 * Given the time of write for an update in a critical section, this method provides a transformed timestamp
616 * that ensures that a previous lock holder who is still alive can never corrupt a later critical section.
617 * The main idea is to us the lock reference to clearly demarcate the timestamps across critical sections.
618 * @param the UUID lock reference associated with the write.
619 * @param the long timeOfWrite which is the actual time at which the write took place
620 * @throws MusicServiceException
621 * @throws MusicQueryException
623 public static long v2sTimeStampInMicroseconds(long ordinal, long timeOfWrite) throws MusicServiceException, MusicQueryException {
624 // TODO: use acquire time instead of music eternity epoch
625 long ts = ordinal * MaxLockReferenceTimePart + (timeOfWrite - MusicEternityEpochMillis);
630 public static MusicCoreService getMusicCoreService() {
631 if(getLockUsing().equals(MusicUtil.CASSANDRA))
632 return MusicCassaCore.getInstance();
634 return MusicCassaCore.getInstance();
641 public static Map<String, Object> validateLock(String lockName) {
642 Map<String, Object> resultMap = new HashMap<>();
643 String[] locks = lockName.split("\\.");
644 if(locks.length < 3) {
645 resultMap.put("Error", "Invalid lock. Please make sure lock is of the type keyspaceName.tableName.primaryKey");
648 String keyspace= locks[0];
649 if(keyspace.startsWith("$"))
650 keyspace = keyspace.substring(1);
651 resultMap.put("keyspace",keyspace);
656 public static void setIsCadi(boolean isCadi) {
657 MusicUtil.isCadi = isCadi;
660 public static void writeBackToQuorum(PreparedQueryObject selectQuery, String primaryKeyName,
661 PreparedQueryObject updateQuery, String keyspace, String table,
662 Object cqlFormattedPrimaryKeyValue)
665 ResultSet results = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(selectQuery);
666 // write it back to a quorum
667 Row row = results.one();
668 ColumnDefinitions colInfo = row.getColumnDefinitions();
669 int totalColumns = colInfo.size();
671 StringBuilder fieldValueString = new StringBuilder("");
672 for (Definition definition : colInfo) {
673 String colName = definition.getName();
674 if (colName.equals(primaryKeyName))
676 DataType colType = definition.getType();
677 Object valueObj = MusicDataStoreHandle.getDSHandle().getColValue(row, colName, colType);
678 Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
679 fieldValueString.append(colName + " = ?");
680 updateQuery.addValue(valueString);
681 if (counter != (totalColumns - 1))
682 fieldValueString.append(",");
683 counter = counter + 1;
685 updateQuery.appendQueryString("UPDATE " + keyspace + "." + table + " SET "
686 + fieldValueString + " WHERE " + primaryKeyName + "= ? " + ";");
687 updateQuery.addValue(cqlFormattedPrimaryKeyValue);
689 MusicDataStoreHandle.getDSHandle().executePut(updateQuery, "critical");
690 } catch (MusicServiceException | MusicQueryException e) {
691 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.QUERYERROR +""+updateQuery ,
692 ErrorSeverity.MAJOR, ErrorTypes.QUERYERROR, e);
696 public static boolean getIsCadi() {
697 return MusicUtil.isCadi;
702 * @return a random uuid
704 public static String generateUUID() {
705 String uuid = UUID.randomUUID().toString();
706 logger.info(EELFLoggerDelegate.applicationLogger,"New AID generated: "+uuid);
710 private static String checkPrefix(String prefix){
711 if (prefix == null || "".equals(prefix) || prefix.endsWith("-")) {
719 * @return the transIdPrefix
721 public static String getTransIdPrefix() {
722 return transIdPrefix;
726 * @param transIdPrefix the transIdPrefix to set
728 public static void setTransIdPrefix(String transIdPrefix) {
729 MusicUtil.transIdPrefix = checkPrefix(transIdPrefix);
733 * @return the conversationIdPrefix
735 public static String getConversationIdPrefix() {
736 return conversationIdPrefix;
740 * @param conversationIdPrefix the conversationIdPrefix to set
742 public static void setConversationIdPrefix(String conversationIdPrefix) {
743 MusicUtil.conversationIdPrefix = checkPrefix(conversationIdPrefix);
747 * @return the clientIdPrefix
749 public static String getClientIdPrefix() {
750 return clientIdPrefix;
754 * @param clientIdPrefix the clientIdPrefix to set
756 public static void setClientIdPrefix(String clientIdPrefix) {
757 MusicUtil.clientIdPrefix = checkPrefix(clientIdPrefix);
761 * @return the messageIdPrefix
763 public static String getMessageIdPrefix() {
764 return messageIdPrefix;
768 * @param messageIdPrefix the messageIdPrefix to set
770 public static void setMessageIdPrefix(String messageIdPrefix) {
771 MusicUtil.messageIdPrefix = checkPrefix(messageIdPrefix);
775 * @return the transIdRequired
777 public static Boolean getTransIdRequired() {
778 return transIdRequired;
783 * @param transIdRequired the transIdRequired to set
785 public static void setTransIdRequired(Boolean transIdRequired) {
786 MusicUtil.transIdRequired = transIdRequired;
791 * @return the conversationIdRequired
793 public static Boolean getConversationIdRequired() {
794 return conversationIdRequired;
799 * @param conversationIdRequired the conversationIdRequired to set
801 public static void setConversationIdRequired(Boolean conversationIdRequired) {
802 MusicUtil.conversationIdRequired = conversationIdRequired;
807 * @return the clientIdRequired
809 public static Boolean getClientIdRequired() {
810 return clientIdRequired;
815 * @param clientIdRequired the clientIdRequired to set
817 public static void setClientIdRequired(Boolean clientIdRequired) {
818 MusicUtil.clientIdRequired = clientIdRequired;
823 * @return the messageIdRequired
825 public static Boolean getMessageIdRequired() {
826 return messageIdRequired;
830 * @param messageIdRequired the messageIdRequired to set
832 public static void setMessageIdRequired(Boolean messageIdRequired) {
833 MusicUtil.messageIdRequired = messageIdRequired;
837 * @return the sleep time, in milliseconds, for the lock cleanup daemon
839 public static long getLockDaemonSleepTimeMs() {
840 return lockDaemonSleepms;
844 * set the sleep time, in milliseconds, for the lock cleanup daemon
846 public static void setLockDaemonSleepTimeMs(long timeoutms) {
847 MusicUtil.lockDaemonSleepms = timeoutms;
850 public static Set<String> getKeyspacesToCleanLocks() {
851 return keyspacesToCleanLocks;
854 public static void setKeyspacesToCleanLocks(Set<String> keyspaces) {
855 MusicUtil.keyspacesToCleanLocks = keyspaces;
858 public static String getCipherEncKey() {
859 return MusicUtil.cipherEncKey;
863 public static void setCipherEncKey(String cipherEncKey) {
864 MusicUtil.cipherEncKey = cipherEncKey;
865 if ( null == cipherEncKey || cipherEncKey.equals("") ||
866 cipherEncKey.equals("nothing to see here")) {
867 logger.error(EELFLoggerDelegate.errorLogger, "Missing Cipher Encryption Key.");
871 public static String getMusicAafNs() {
872 return MusicUtil.musicAafNs;
876 public static void setMusicAafNs(String musicAafNs) {
877 MusicUtil.musicAafNs = musicAafNs;