2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (c) 2017 AT&T Intellectual Property
6 * ===================================================================
7 * Modifications Copyright (c) 2018 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.io.IOException;
35 import java.io.InputStream;
36 import java.math.BigInteger;
37 import java.nio.ByteBuffer;
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.List;
42 import java.util.Properties;
43 import java.util.Scanner;
44 import java.util.StringTokenizer;
45 import java.util.UUID;
46 import java.util.concurrent.ConcurrentHashMap;
47 import java.util.concurrent.ConcurrentMap;
49 import javax.ws.rs.core.Response;
50 import javax.ws.rs.core.Response.ResponseBuilder;
51 import org.onap.music.datastore.MusicDataStoreHandle;
52 import org.onap.music.datastore.PreparedQueryObject;
53 import org.onap.music.eelf.logging.EELFLoggerDelegate;
54 import org.onap.music.eelf.logging.format.AppMessages;
55 import org.onap.music.eelf.logging.format.ErrorSeverity;
56 import org.onap.music.eelf.logging.format.ErrorTypes;
57 import org.onap.music.exceptions.MusicQueryException;
58 import org.onap.music.exceptions.MusicServiceException;
59 import org.onap.music.service.MusicCoreService;
60 import org.onap.music.service.impl.MusicCassaCore;
62 import com.datastax.driver.core.ConsistencyLevel;
63 import com.datastax.driver.core.DataType;
64 import com.sun.jersey.core.util.Base64;
69 * Properties This will take Properties and load them into MusicUtil.
70 * This is a hack for now. Eventually it would bebest to do this in
74 public class MusicUtil {
75 private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicUtil.class);
77 // Consistancy Constants
78 public static final String ATOMIC = "atomic";
79 public static final String EVENTUAL = "eventual";
80 public static final String CRITICAL = "critical";
81 public static final String EVENTUAL_NB = "eventual_nb";
82 public static final String ALL = "all";
83 public static final String QUORUM = "quorum";
84 public static final String ONE = "one";
85 public static final String ATOMICDELETELOCK = "atomic_delete_lock";
88 private static final String XLATESTVERSION = "X-latestVersion";
89 private static final String XMINORVERSION = "X-minorVersion";
90 private static final String XPATCHVERSION = "X-patchVersion";
91 public static final String AUTHORIZATION = "Authorization";
94 public static final String SELECT = "select";
95 public static final String INSERT = "insert";
96 public static final String UPDATE = "update";
97 public static final String UPSERT = "upsert";
98 public static final String USERID = "userId";
99 public static final String PASSWORD = "";
100 public static final String CASSANDRA = "cassandra";
102 private static final String LOCALHOST = "localhost";
103 private static final String PROPERTIES_FILE = "/opt/app/music/etc/music.properties";
104 public static final String DEFAULTKEYSPACENAME = "TBD";
106 private static String myCassaHost = LOCALHOST;
107 private static String defaultMusicIp = LOCALHOST;
108 private static int cassandraPort = 9042;
109 private static int notifytimeout = 30000;
110 private static int notifyinterval = 5000;
111 private static long defaultLockLeasePeriod = 6000;
112 private static int retryCount = 3;
113 private static int cacheObjectMaxLife = -1;
114 private static String lockUsing = MusicUtil.CASSANDRA;
115 private static boolean isCadi = false;
116 private static boolean isKeyspaceActive = false;
117 private static boolean debug = true;
118 private static String version = "0.0.0";
119 private static String build = "";
121 private static String musicPropertiesFilePath = PROPERTIES_FILE;
122 private static final String[] propKeys = new String[] { "cassandra.host", "music.ip", "debug",
123 "version", "music.rest.ip", "music.properties", "lock.lease.period", "id", "all.ids",
124 "public.ip","all.pubic.ips", "cassandra.user", "cassandra.password", "aaf.endpoint.url",
125 "admin.username","admin.password","aaf.admin.url","music.namespace","admin.aaf.role",
126 "cassandra.port","lock.using","retry.count","transId.header.required",
127 "conversation.header.required","clientId.header.required","messageId.header.required",
128 "transId.header.prefix","conversation.header.prefix","clientId.header.prefix",
129 "messageId.header.prefix"};
130 private static final String[] cosistencyLevel = new String[] {
131 "ALL","EACH_QUORUM","QUORUM","LOCAL_QUORUM","ONE","TWO",
132 "THREE","LOCAL_ONE","ANY","SERIAL","LOCAL_SERIAL"};
133 private static final Map<String,ConsistencyLevel> consistencyName = new HashMap<>();
135 consistencyName.put("ONE",ConsistencyLevel.ONE);
136 consistencyName.put("TWO",ConsistencyLevel.TWO);
137 consistencyName.put("THREE",ConsistencyLevel.THREE);
138 consistencyName.put("SERIAL",ConsistencyLevel.SERIAL);
139 consistencyName.put("ALL",ConsistencyLevel.ALL);
140 consistencyName.put("EACH_QUORUM",ConsistencyLevel.EACH_QUORUM);
141 consistencyName.put("QUORUM",ConsistencyLevel.QUORUM);
142 consistencyName.put("LOCAL_QUORUM",ConsistencyLevel.LOCAL_QUORUM);
143 consistencyName.put("LOCAL_ONE",ConsistencyLevel.LOCAL_ONE);
144 consistencyName.put("LOCAL_SERIAL",ConsistencyLevel.LOCAL_SERIAL);
146 private static String cassName = "cassandra";
147 private static String cassPwd;
148 private static String aafEndpointUrl = null;
149 private static String adminId = "username";
150 private static String adminPass= "password";
151 private static String aafAdminUrl= null;
152 private static String musicNamespace= "org.onap.music.api";
153 private static String adminAafRole= "org.onap.music.api.admin_api";
155 public static final long MusicEternityEpochMillis = 1533081600000L; // Wednesday, August 1, 2018 12:00:00 AM
156 public static final long MaxLockReferenceTimePart = 1000000000000L; // millis after eternity (eq sometime in 2050)
157 public static final long MaxCriticalSectionDurationMillis = 1L * 24 * 60 * 60 * 1000; // 1 day
159 private static String transIdPrefix= "false";
160 private static String conversationIdPrefix= "false";
161 private static String clientIdPrefix= "false";
162 private static String messageIdPrefix= "false";
163 private static String transIdRequired= "false";
164 private static String conversationIdRequired= "false";
165 private static String clientIdRequired= "false";
166 private static String messageIdRequired= "false";
168 public static String getLockUsing() {
173 public static void setLockUsing(String lockUsing) {
174 MusicUtil.lockUsing = lockUsing;
177 public static String getAafAdminUrl() {
182 public static void setAafAdminUrl(String aafAdminUrl) {
183 MusicUtil.aafAdminUrl = aafAdminUrl;
187 public static String getMusicNamespace() {
188 return musicNamespace;
192 public static void setMusicNamespace(String musicNamespace) {
193 MusicUtil.musicNamespace = musicNamespace;
197 public static String getAdminAafRole() {
202 public static void setAdminAafRole(String adminAafRole) {
203 MusicUtil.adminAafRole = adminAafRole;
208 public static String getAdminId() {
213 public static void setAdminId(String adminId) {
214 MusicUtil.adminId = adminId;
218 public static String getAdminPass() {
222 public static void setAdminPass(String adminPass) {
223 MusicUtil.adminPass = adminPass;
226 private MusicUtil() {
227 throw new IllegalStateException("Utility Class");
231 * @return cassandra port
233 public static int getCassandraPort() {
234 return cassandraPort;
239 * @param cassandraPort
241 public static void setCassandraPort(int cassandraPort) {
242 MusicUtil.cassandraPort = cassandraPort;
245 * @return the cassName
247 public static String getCassName() {
252 * @return the cassPwd
254 public static String getCassPwd() {
259 * @return the aafEndpointUrl
261 public static String getAafEndpointUrl() {
262 return aafEndpointUrl;
267 * @param aafEndpointUrl
269 public static void setAafEndpointUrl(String aafEndpointUrl) {
270 MusicUtil.aafEndpointUrl = aafEndpointUrl;
275 * Returns An array of property names that should be in the Properties
280 public static String[] getPropkeys() {
281 return propKeys.clone();
285 * Get MusicPropertiesFilePath - Default = /opt/music/music.properties
286 * property file value - music.properties
290 public static String getMusicPropertiesFilePath() {
291 return musicPropertiesFilePath;
295 * Set MusicPropertiesFilePath
297 * @param musicPropertiesFilePath
299 public static void setMusicPropertiesFilePath(String musicPropertiesFilePath) {
300 MusicUtil.musicPropertiesFilePath = musicPropertiesFilePath;
304 * Get DefaultLockLeasePeriod - Default = 6000 property file value -
309 public static long getDefaultLockLeasePeriod() {
310 return defaultLockLeasePeriod;
314 * Set DefaultLockLeasePeriod
316 * @param defaultLockLeasePeriod
318 public static void setDefaultLockLeasePeriod(long defaultLockLeasePeriod) {
319 MusicUtil.defaultLockLeasePeriod = defaultLockLeasePeriod;
327 public static void setDebug(boolean debug) {
328 MusicUtil.debug = debug;
332 * Is Debug - Default = true property file value - debug
336 public static boolean isDebug() {
345 public static void setVersion(String version) {
346 MusicUtil.version = version;
350 * Return the version property file value - version.
354 public static String getVersion() {
359 * Set the build of project which is a combination of the
360 * version and the date.
362 * @param build - version-date.
364 public static void setBuild(String build) {
365 MusicUtil.build = build;
369 * Return the build version-date.
371 public static String getBuild() {
376 * Get MyCassHost - Cassandra Hostname - Default = localhost property file
377 * value - cassandra.host
381 public static String getMyCassaHost() {
386 * Set MyCassHost - Cassandra Hostname
388 * @param myCassaHost .
390 public static void setMyCassaHost(String myCassaHost) {
391 MusicUtil.myCassaHost = myCassaHost;
395 * Get DefaultMusicIp - Default = localhost property file value - music.ip
399 public static String getDefaultMusicIp() {
400 return defaultMusicIp;
406 * @param defaultMusicIp .
408 public static void setDefaultMusicIp(String defaultMusicIp) {
409 MusicUtil.defaultMusicIp = defaultMusicIp;
413 * Gey default retry count
416 public static int getRetryCount() {
422 * @param retryCount .
424 public static void setRetryCount(int retryCount) {
425 MusicUtil.retryCount = retryCount;
430 * This is used to turn keyspace creation api on/off.
433 public static void setKeyspaceActive(Boolean keyspaceActive) {
434 MusicUtil.isKeyspaceActive = keyspaceActive;
438 * This is used to turn keyspace creation api on/off.
439 * @return boolean isKeyspaceActive
441 public static boolean isKeyspaceActive() {
442 return isKeyspaceActive;
449 public static String getTestType() {
450 String testType = "";
452 Scanner fileScanner = new Scanner(new File(""));
453 testType = fileScanner.next();// ignore the my id line
454 @SuppressWarnings("unused")
455 String batchSize = fileScanner.next();// ignore the my public ip line
457 } catch (FileNotFoundException e) {
458 logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e);
468 public static void sleep(long time) {
471 } catch (InterruptedException e) {
472 logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e);
473 Thread.currentThread().interrupt();
478 * Utility function to check if the query object is valid.
484 public static boolean isValidQueryObject(boolean withparams, PreparedQueryObject queryObject) {
486 int noOfValues = queryObject.getValues().size();
488 char[] temp = queryObject.getQuery().toCharArray();
489 for (int i = 0; i < temp.length; i++) {
493 return (noOfValues == noOfParams);
495 return !queryObject.getQuery().isEmpty();
500 public static void setCassName(String cassName) {
501 MusicUtil.cassName = cassName;
504 public static void setCassPwd(String cassPwd) {
505 MusicUtil.cassPwd = cassPwd;
508 @SuppressWarnings("unchecked")
509 public static String convertToCQLDataType(DataType type, Object valueObj) throws Exception {
512 switch (type.getName()) {
514 value = valueObj + "";
518 String valueString = valueObj + "";
519 valueString = valueString.replace("'", "''");
520 value = "'" + valueString + "'";
523 Map<String, Object> otMap = (Map<String, Object>) valueObj;
524 value = "{" + jsonMaptoSqlString(otMap, ",") + "}";
528 value = valueObj + "";
539 * @throws MusicTypeConversionException
542 @SuppressWarnings("unchecked")
543 public static Object convertToActualDataType(DataType colType, Object valueObj) throws Exception {
544 String valueObjString = valueObj + "";
545 switch (colType.getName()) {
547 return UUID.fromString(valueObjString);
549 return BigInteger.valueOf(Long.parseLong(valueObjString));
551 return Long.parseLong(valueObjString);
553 return Integer.parseInt(valueObjString);
555 return Float.parseFloat(valueObjString);
557 return Double.parseDouble(valueObjString);
559 return Boolean.parseBoolean(valueObjString);
561 return (Map<String, Object>) valueObj;
563 return (List<Object>)valueObj;
567 return valueObjString;
571 public static ByteBuffer convertToActualDataType(DataType colType, byte[] valueObj) {
572 ByteBuffer buffer = ByteBuffer.wrap(valueObj);
578 * Utility function to parse json map into sql like string
581 * @param lineDelimiter
585 public static String jsonMaptoSqlString(Map<String, Object> jMap, String lineDelimiter) throws Exception{
586 StringBuilder sqlString = new StringBuilder();
588 for (Map.Entry<String, Object> entry : jMap.entrySet()) {
589 Object ot = entry.getValue();
590 String value = ot + "";
591 if (ot instanceof String) {
592 value = "'" + value.replace("'", "''") + "'";
594 sqlString.append("'" + entry.getKey() + "':" + value);
595 if (counter != jMap.size() - 1)
596 sqlString.append(lineDelimiter);
597 counter = counter + 1;
599 return sqlString.toString();
602 @SuppressWarnings("unused")
603 public static String buildVersion(String major, String minor, String patch) {
605 major += "." + minor;
607 major += "." + patch;
614 * Currently this will build a header with X-latestVersion, X-minorVersion and X-pathcVersion
615 * X-latestVerstion will be equal to the latest full version.
616 * X-minorVersion - will be equal to the latest minor version.
617 * X-pathVersion - will be equal to the latest patch version.
618 * Future plans will change this.
625 public static ResponseBuilder buildVersionResponse(String major, String minor, String patch) {
626 ResponseBuilder response = Response.noContent();
627 String versionIn = buildVersion(major,minor,patch);
628 String version = MusicUtil.getVersion();
629 String[] verArray = version.split("\\.",3);
630 if ( minor != null ) {
631 response.header(XMINORVERSION,minor);
633 response.header(XMINORVERSION,verArray[1]);
635 if ( patch != null ) {
636 response.header(XPATCHVERSION,patch);
638 response.header(XPATCHVERSION,verArray[2]);
640 response.header(XLATESTVERSION,version);
641 logger.info(EELFLoggerDelegate.applicationLogger,"Version In:" + versionIn);
645 public static boolean isValidConsistency(String consistency) {
646 for (String string : cosistencyLevel) {
647 if (string.equalsIgnoreCase(consistency))
654 public static ConsistencyLevel getConsistencyLevel(String consistency) {
655 return consistencyName.get(consistency.toUpperCase());
658 public static void loadProperties() throws Exception {
659 Properties prop = new Properties();
660 InputStream input = null;
662 // load the properties file
663 input = MusicUtil.class.getClassLoader().getResourceAsStream("music.properties");
665 } catch (Exception ex) {
666 logger.error(EELFLoggerDelegate.errorLogger, "Unable to find properties file.", ex);
667 throw new Exception();
672 } catch (IOException e) {
674 logger.error(EELFLoggerDelegate.errorLogger, e);
678 // get the property value and return it
679 MusicUtil.setMyCassaHost(prop.getProperty("cassandra.host"));
680 MusicUtil.setCassName(prop.getProperty("cassandra.user"));
681 MusicUtil.setCassPwd(prop.getProperty("cassandra.password"));
682 MusicUtil.setCassandraPort(Integer.parseInt(prop.getProperty("cassandra.port")));
683 MusicUtil.setNotifyTimeOut(Integer.parseInt(prop.getProperty("notify.timeout")));
684 MusicUtil.setNotifyInterval(Integer.parseInt(prop.getProperty("notify.interval")));
685 MusicUtil.setCacheObjectMaxLife(Integer.parseInt(prop.getProperty("cacheobject.maxlife")));
688 public static void setNotifyInterval(int notifyinterval) {
689 MusicUtil.notifyinterval = notifyinterval;
691 public static void setNotifyTimeOut(int notifytimeout) {
692 MusicUtil.notifytimeout = notifytimeout;
695 public static int getNotifyInterval() {
696 return MusicUtil.notifyinterval;
699 public static int getNotifyTimeout() {
700 return MusicUtil.notifytimeout;
703 public static int getCacheObjectMaxLife() {
704 return MusicUtil.cacheObjectMaxLife;
707 public static void setCacheObjectMaxLife(int cacheObjectMaxLife) {
708 MusicUtil.cacheObjectMaxLife = cacheObjectMaxLife;
712 * Given the time of write for an update in a critical section, this method provides a transformed timestamp
713 * that ensures that a previous lock holder who is still alive can never corrupt a later critical section.
714 * The main idea is to us the lock reference to clearly demarcate the timestamps across critical sections.
715 * @param the UUID lock reference associated with the write.
716 * @param the long timeOfWrite which is the actual time at which the write took place
717 * @throws MusicServiceException
718 * @throws MusicQueryException
720 public static long v2sTimeStampInMicroseconds(long ordinal, long timeOfWrite) throws MusicServiceException, MusicQueryException {
721 // TODO: use acquire time instead of music eternity epoch
722 long ts = ordinal * MaxLockReferenceTimePart + (timeOfWrite - MusicEternityEpochMillis);
727 public static MusicCoreService getMusicCoreService() {
728 if(getLockUsing().equals(MusicUtil.CASSANDRA))
729 return MusicCassaCore.getInstance();
731 return MusicCassaCore.getInstance();
738 public static Map<String, Object> validateLock(String lockName) {
739 Map<String, Object> resultMap = new HashMap<>();
740 String[] locks = lockName.split("\\.");
741 if(locks.length < 3) {
742 resultMap.put("Error", "Invalid lock. Please make sure lock is of the type keyspaceName.tableName.primaryKey");
745 String keyspace= locks[0];
746 if(keyspace.startsWith("$"))
747 keyspace = keyspace.substring(1);
748 resultMap.put("keyspace",keyspace);
753 public static void setIsCadi(boolean isCadi) {
754 MusicUtil.isCadi = isCadi;
757 public static void writeBackToQuorum(PreparedQueryObject selectQuery, String primaryKeyName,
758 PreparedQueryObject updateQuery, String keyspace, String table,
759 Object cqlFormattedPrimaryKeyValue)
762 ResultSet results = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(selectQuery);
763 // write it back to a quorum
764 Row row = results.one();
765 ColumnDefinitions colInfo = row.getColumnDefinitions();
766 int totalColumns = colInfo.size();
768 StringBuilder fieldValueString = new StringBuilder("");
769 for (Definition definition : colInfo) {
770 String colName = definition.getName();
771 if (colName.equals(primaryKeyName))
773 DataType colType = definition.getType();
774 Object valueObj = MusicDataStoreHandle.getDSHandle().getColValue(row, colName, colType);
775 Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
776 fieldValueString.append(colName + " = ?");
777 updateQuery.addValue(valueString);
778 if (counter != (totalColumns - 1))
779 fieldValueString.append(",");
780 counter = counter + 1;
782 updateQuery.appendQueryString("UPDATE " + keyspace + "." + table + " SET "
783 + fieldValueString + " WHERE " + primaryKeyName + "= ? " + ";");
784 updateQuery.addValue(cqlFormattedPrimaryKeyValue);
786 MusicDataStoreHandle.getDSHandle().executePut(updateQuery, "critical");
787 } catch (MusicServiceException | MusicQueryException e) {
788 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.QUERYERROR +""+updateQuery ,
789 ErrorSeverity.MAJOR, ErrorTypes.QUERYERROR, e);
793 public static boolean getIsCadi() {
794 return MusicUtil.isCadi;
799 * @return a random uuid
801 public static String generateUUID() {
802 String uuid = UUID.randomUUID().toString();
803 logger.info(EELFLoggerDelegate.applicationLogger,"New AID generated: "+uuid);
807 private static String checkPrefix(String prefix){
808 if (prefix == null || "".equals(prefix) || prefix.endsWith("-")) {
816 * @return the transIdPrefix
818 public static String getTransIdPrefix() {
819 return transIdPrefix;
823 * @param transIdPrefix the transIdPrefix to set
825 public static void setTransIdPrefix(String transIdPrefix) {
826 MusicUtil.transIdPrefix = checkPrefix(transIdPrefix);
830 * @return the conversationIdPrefix
832 public static String getConversationIdPrefix() {
833 return conversationIdPrefix;
837 * @param conversationIdPrefix the conversationIdPrefix to set
839 public static void setConversationIdPrefix(String conversationIdPrefix) {
840 MusicUtil.conversationIdPrefix = checkPrefix(conversationIdPrefix);
844 * @return the clientIdPrefix
846 public static String getClientIdPrefix() {
847 return clientIdPrefix;
851 * @param clientIdPrefix the clientIdPrefix to set
853 public static void setClientIdPrefix(String clientIdPrefix) {
854 MusicUtil.clientIdPrefix = checkPrefix(clientIdPrefix);
858 * @return the messageIdPrefix
860 public static String getMessageIdPrefix() {
861 return messageIdPrefix;
865 * @param messageIdPrefix the messageIdPrefix to set
867 public static void setMessageIdPrefix(String messageIdPrefix) {
868 MusicUtil.messageIdPrefix = checkPrefix(messageIdPrefix);
872 * @return the transIdRequired
874 public static String getTransIdRequired() {
875 return transIdRequired;
880 * @param transIdRequired the transIdRequired to set
882 public static void setTransIdRequired(String transIdRequired) {
883 MusicUtil.transIdRequired = transIdRequired;
888 * @return the conversationIdRequired
890 public static String getConversationIdRequired() {
891 return conversationIdRequired;
896 * @param conversationIdRequired the conversationIdRequired to set
898 public static void setConversationIdRequired(String conversationIdRequired) {
899 MusicUtil.conversationIdRequired = conversationIdRequired;
904 * @return the clientIdRequired
906 public static String getClientIdRequired() {
907 return clientIdRequired;
912 * @param clientIdRequired the clientIdRequired to set
914 public static void setClientIdRequired(String clientIdRequired) {
915 MusicUtil.clientIdRequired = clientIdRequired;
920 * @return the messageIdRequired
922 public static String getMessageIdRequired() {
923 return messageIdRequired;
928 * @param messageIdRequired the messageIdRequired to set
930 public static void setMessageIdRequired(String messageIdRequired) {
931 MusicUtil.messageIdRequired = messageIdRequired;