From e99b7fa829bf957c2a46223a1a20a32aebeda91b Mon Sep 17 00:00:00 2001 From: arthurdent3 Date: Fri, 2 Feb 2018 21:19:53 -0500 Subject: Initial code Import. Issue-ID: MUSIC-21 Change-Id: I89ceab0891b4b7cb999dab532d6bae9092f027cc Signed-off-by: arthurdent3 --- src/main/java/org/onap/music/main/CachingUtil.java | 370 +++++++++ .../java/org/onap/music/main/CronJobManager.java | 47 ++ src/main/java/org/onap/music/main/MusicCore.java | 874 +++++++++++++++++++++ src/main/java/org/onap/music/main/MusicDigest.java | 78 ++ src/main/java/org/onap/music/main/MusicUtil.java | 465 +++++++++++ .../org/onap/music/main/PropertiesListener.java | 147 ++++ src/main/java/org/onap/music/main/ResultType.java | 39 + src/main/java/org/onap/music/main/ReturnType.java | 74 ++ 8 files changed, 2094 insertions(+) create mode 100755 src/main/java/org/onap/music/main/CachingUtil.java create mode 100644 src/main/java/org/onap/music/main/CronJobManager.java create mode 100644 src/main/java/org/onap/music/main/MusicCore.java create mode 100644 src/main/java/org/onap/music/main/MusicDigest.java create mode 100755 src/main/java/org/onap/music/main/MusicUtil.java create mode 100755 src/main/java/org/onap/music/main/PropertiesListener.java create mode 100644 src/main/java/org/onap/music/main/ResultType.java create mode 100644 src/main/java/org/onap/music/main/ReturnType.java (limited to 'src/main/java/org/onap/music/main') diff --git a/src/main/java/org/onap/music/main/CachingUtil.java b/src/main/java/org/onap/music/main/CachingUtil.java new file mode 100755 index 00000000..0ab055df --- /dev/null +++ b/src/main/java/org/onap/music/main/CachingUtil.java @@ -0,0 +1,370 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.jcs.JCS; +import org.apache.commons.jcs.access.CacheAccess; +import org.apache.log4j.Logger; +import org.codehaus.jackson.map.ObjectMapper; +import org.onap.music.datastore.jsonobjects.AAFResponse; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.onap.music.datastore.PreparedQueryObject; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; + +/** + * All Caching related logic is handled by this class and a schedule cron runs to update cache. + * + * @author Vikram + * + */ +public class CachingUtil implements Runnable { + + private static EELFLogger logger = EELFManager.getInstance().getLogger(CachingUtil.class); + + private static CacheAccess musicCache = JCS.getInstance("musicCache"); + private static CacheAccess> aafCache = JCS.getInstance("aafCache"); + private static CacheAccess appNameCache = JCS.getInstance("appNameCache"); + private static Map userAttempts = new HashMap<>(); + private static Map lastFailedTime = new HashMap<>(); + + public boolean isCacheRefreshNeeded() { + if (aafCache.get("initBlankMap") == null) + return true; + return false; + } + + public void initializeMusicCache() { + logger.info("Initializing Music Cache..."); + musicCache.put("isInitialized", "true"); + } + + public void initializeAafCache() { + logger.info("Resetting and initializing AAF Cache..."); + + // aafCache.clear(); + // loop through aafCache ns .. only the authenticated ns will be re cached. and non + // authenticated will wait for user to retry. + String query = "SELECT application_name, keyspace_name, username, password FROM admin.keyspace_master WHERE is_api = ? allow filtering"; + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString(query); + try { + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), false)); + } catch (Exception e1) { + e1.printStackTrace(); + logger.error("Exception is " + e1.getMessage() + "during initalizeAafCache"); + } + ResultSet rs = MusicCore.get(pQuery); + Iterator it = rs.iterator(); + Map map = null; + while (it.hasNext()) { + Row row = it.next(); + String nameSpace = row.getString("keyspace_name"); + String userId = row.getString("username"); + String password = row.getString("password"); + String keySpace = row.getString("application_name"); + try { + userAttempts.put(nameSpace, 0); + AAFResponse responseObj = triggerAAF(nameSpace, userId, password); + if (responseObj.getNs().size() > 0) { + map = new HashMap<>(); + map.put(userId, password); + aafCache.put(nameSpace, map); + musicCache.put(nameSpace, keySpace); + logger.debug("Cronjob: Cache Updated with AAF response for namespace " + + nameSpace); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + logger.error("Something at AAF was changed for ns: " + nameSpace + + ". So not updating Cache for the namespace. "); + logger.error("Exception is " + e.getMessage()); + } + } + + } + + @Override + public void run() { + logger.debug("Scheduled task invoked. Refreshing Cache..."); + initializeAafCache(); + } + + public static boolean authenticateAAFUser(String nameSpace, String userId, String password, + String keySpace) throws Exception { + + if (aafCache.get(nameSpace) != null) { + if (!musicCache.get(nameSpace).equals(keySpace)) { + logger.debug("Create new application for the same namespace."); + } else if (aafCache.get(nameSpace).get(userId).equals(password)) { + logger.debug("Authenticated with cache value.."); + // reset invalid attempts to 0 + userAttempts.put(nameSpace, 0); + return true; + } else { + // call AAF update cache with new password + if (userAttempts.get(nameSpace) == null) + userAttempts.put(nameSpace, 0); + if ((Integer) userAttempts.get(nameSpace) >= 3) { + logger.info("Reached max attempts. Checking if time out.."); + logger.info("Failed time: " + lastFailedTime.get(nameSpace).getTime()); + Calendar calendar = Calendar.getInstance(); + long delayTime = (calendar.getTimeInMillis() + - lastFailedTime.get(nameSpace).getTimeInMillis()); + logger.info("Delayed time: " + delayTime); + if (delayTime > 120000) { + logger.info("Resetting failed attempt."); + userAttempts.put(nameSpace, 0); + } else { + throw new Exception( + "No more attempts allowed. Please wait for atleast 2 min."); + } + } + logger.error("Cache not authenticated.."); + logger.info("Check AAF again..."); + } + } + + AAFResponse responseObj = triggerAAF(nameSpace, userId, password); + if (responseObj.getNs().size() > 0) { + if (responseObj.getNs().get(0).getAdmin().contains(userId)) + return true; + + } + logger.info("Invalid user. Cache not updated"); + return false; + } + + private static AAFResponse triggerAAF(String nameSpace, String userId, String password) + throws Exception { + if (MusicUtil.getAafEndpointUrl() == null) { + throw new Exception("AAF endpoint is not set. Please specify in the properties file."); + } + Client client = Client.create(); + // WebResource webResource = + // client.resource("https://aaftest.test.att.com:8095/proxy/authz/nss/"+nameSpace); + WebResource webResource = client.resource(MusicUtil.getAafEndpointUrl().concat(nameSpace)); + String plainCreds = userId + ":" + password; + byte[] plainCredsBytes = plainCreds.getBytes(); + byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); + String base64Creds = new String(base64CredsBytes); + + ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON) + .header("Authorization", "Basic " + base64Creds) + .header("content-type", "application/json").get(ClientResponse.class); + if (response.getStatus() != 200) { + if (userAttempts.get(nameSpace) == null) + userAttempts.put(nameSpace, 0); + if ((Integer) userAttempts.get(nameSpace) >= 2) { + lastFailedTime.put(nameSpace, Calendar.getInstance()); + userAttempts.put(nameSpace, ((Integer) userAttempts.get(nameSpace) + 1)); + throw new Exception( + "Reached max invalid attempts. Please contact admin and retry with valid credentials."); + } + userAttempts.put(nameSpace, ((Integer) userAttempts.get(nameSpace) + 1)); + throw new Exception( + "Unable to authenticate. Please check the AAF credentials against namespace."); + // TODO Allow for 2-3 times and forbid any attempt to trigger AAF with invalid values + // for specific time. + } + response.getHeaders().put(HttpHeaders.CONTENT_TYPE, + Arrays.asList(MediaType.APPLICATION_JSON)); + // AAFResponse output = response.getEntity(AAFResponse.class); + response.bufferEntity(); + String x = response.getEntity(String.class); + AAFResponse responseObj = new ObjectMapper().readValue(x, AAFResponse.class); + return responseObj; + } + + public static Map authenticateAIDUser(String aid, String keyspace) + throws Exception { + Map resultMap = new HashMap<>(); + String uuid = null; + /* + * if(aid == null || aid.length() == 0) { resultMap.put("Exception Message", + * "AID is missing for the keyspace requested."); //create a new AID ?? } else + */ + if (musicCache.get(keyspace) == null) { + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "SELECT uuid from admin.keyspace_master where keyspace_name = '" + + keyspace + "' allow filtering"); + Row rs = MusicCore.get(pQuery).one(); + try { + uuid = rs.getUUID("uuid").toString(); + musicCache.put(keyspace, uuid); + } catch (Exception e) { + String msg = e.getMessage(); + logger.error("Exception occured during uuid retrieval from DB." + e.getMessage()); + resultMap.put("Exception", "Unauthorized operation. Check AID and Keyspace. " + + "Exception from MUSIC is: " + + (msg == null ? "Keyspace is new so no AID should be passed in Header." + : msg)); + return resultMap; + } + if (!musicCache.get(keyspace).toString().equals(aid)) { + resultMap.put("Exception Message", + "Unauthorized operation. Invalid AID for the keyspace"); + return resultMap; + } + } else if (musicCache.get(keyspace) != null + && !musicCache.get(keyspace).toString().equals(aid)) { + resultMap.put("Exception Message", + "Unauthorized operation. Invalid AID for the keyspace"); + return resultMap; + } + resultMap.put("aid", uuid); + return resultMap; + } + + public static void updateMusicCache(String aid, String keyspace) { + logger.info("Updating musicCache for keyspace " + keyspace + " with aid " + aid); + musicCache.put(keyspace, aid); + } + + public static void updateisAAFCache(String namespace, String isAAF) { + appNameCache.put(namespace, isAAF); + } + + public static Boolean isAAFApplication(String namespace) { + + String isAAF = appNameCache.get(namespace); + if (isAAF == null) { + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "SELECT is_aaf from admin.keyspace_master where application_name = '" + + namespace + "' allow filtering"); + Row rs = MusicCore.get(pQuery).one(); + try { + isAAF = String.valueOf(rs.getBool("is_aaf")); + appNameCache.put(namespace, isAAF); + } catch (Exception e) { + logger.error("Exception occured during uuid retrieval from DB." + e.getMessage()); + e.printStackTrace(); + } + } + return Boolean.valueOf(isAAF); + } + + public static String getUuidFromMusicCache(String keyspace) { + String uuid = musicCache.get(keyspace); + if (uuid == null) { + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "SELECT uuid from admin.keyspace_master where keyspace_name = '" + + keyspace + "' allow filtering"); + Row rs = MusicCore.get(pQuery).one(); + try { + uuid = rs.getUUID("uuid").toString(); + musicCache.put(keyspace, uuid); + } catch (Exception e) { + logger.error("Exception occured during uuid retrieval from DB." + e.getMessage()); + e.printStackTrace(); + } + } + return uuid; + } + + public static String getAppName(String keyspace) { + String appName = null; + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "SELECT application_name from admin.keyspace_master where keyspace_name = '" + + keyspace + "' allow filtering"); + Row rs = MusicCore.get(pQuery).one(); + try { + appName = rs.getString("application_name"); + } catch (Exception e) { + logger.error("Exception occured during uuid retrieval from DB." + e.getMessage()); + e.printStackTrace(); + } + return appName; + } + + public static String generateUUID() { + String uuid = UUID.randomUUID().toString(); + logger.info("New AID generated: " + uuid); + return uuid; + } + + public static Map validateRequest(String nameSpace, String userId, + String password, String keyspace, String aid, String operation) { + Map resultMap = new HashMap<>(); + if (!"createKeySpace".equals(operation)) { + if (nameSpace == null) { + resultMap.put("Exception", "Application namespace is mandatory."); + } + } + return resultMap; + + } + + public static Map verifyOnboarding(String ns, String userId, String password) + throws Exception { + Map resultMap = new HashMap<>(); + if (ns == null || userId == null || password == null) { + logger.error("One or more required headers is missing. userId: " + userId + + " :: password: " + password); + resultMap.put("Exception", + "One or more required headers appName(ns), userId, password is missing. Please check."); + return resultMap; + } + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "select * from admin.keyspace_master where application_name=? and username=? allow filtering"); + queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), ns)); + queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + Row rs = MusicCore.get(queryObject).one(); + if (rs == null) { + logger.error("Namespace and UserId doesn't match. namespace: " + ns + " and userId: " + + userId); + resultMap.put("Exception", "Application " + ns + + " doesn't seem to be Onboarded. Please onboard your application with MUSIC. If already onboarded contact Admin"); + } else { + boolean is_aaf = rs.getBool("is_aaf"); + String keyspace = rs.getString("keyspace_name"); + if (!is_aaf) { + if (!keyspace.equals(MusicUtil.DEFAULTKEYSPACENAME)) { + logger.error("Non AAF applications are allowed to have only one keyspace per application."); + resultMap.put("Exception", + "Non AAF applications are allowed to have only one keyspace per application."); + } + } + } + return resultMap; + } +} diff --git a/src/main/java/org/onap/music/main/CronJobManager.java b/src/main/java/org/onap/music/main/CronJobManager.java new file mode 100644 index 00000000..fb4a2ac3 --- /dev/null +++ b/src/main/java/org/onap/music/main/CronJobManager.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +@WebListener +public class CronJobManager implements ServletContextListener { + + private ScheduledExecutorService scheduler; + + @Override + public void contextInitialized(ServletContextEvent event) { + scheduler = Executors.newSingleThreadScheduledExecutor(); + scheduler.scheduleAtFixedRate(new CachingUtil(), 0, 24, TimeUnit.HOURS); + } + + @Override + public void contextDestroyed(ServletContextEvent event) { + scheduler.shutdownNow(); + } + +} diff --git a/src/main/java/org/onap/music/main/MusicCore.java b/src/main/java/org/onap/music/main/MusicCore.java new file mode 100644 index 00000000..592bae92 --- /dev/null +++ b/src/main/java/org/onap/music/main/MusicCore.java @@ -0,0 +1,874 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + + +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; +import org.onap.music.datastore.MusicDataStore; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.datastore.jsonobjects.JsonKeySpace; +// import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.lockingservice.MusicLockState; +import org.onap.music.lockingservice.MusicLockState.LockStatus; +import org.onap.music.lockingservice.MusicLockingService; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.datastax.driver.core.ColumnDefinitions; +import com.datastax.driver.core.ColumnDefinitions.Definition; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.TableMetadata; + +/** + * This class ..... + * + * + */ +public class MusicCore { + + public static MusicLockingService mLockHandle = null; + public static MusicDataStore mDstoreHandle = null; + private static EELFLogger logger = EELFManager.getInstance().getLogger(MusicCore.class); + + public static class Condition { + Map conditions; + String selectQueryForTheRow; + + public Condition(Map conditions, String selectQueryForTheRow) { + this.conditions = conditions; + this.selectQueryForTheRow = selectQueryForTheRow; + } + + public boolean testCondition() { + // first generate the row + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString(selectQueryForTheRow); + ResultSet results = quorumGet(query); + Row row = results.one(); + return getDSHandle().doesRowSatisfyCondition(row, conditions); + } + } + + + public static MusicLockingService getLockingServiceHandle() throws MusicLockingException { + logger.info("Acquiring lock store handle"); + long start = System.currentTimeMillis(); + + if (mLockHandle == null) { + try { + mLockHandle = new MusicLockingService(); + } catch (Exception e) { + logger.error("Failed to aquire Locl store handle" + e.getMessage()); + throw new MusicLockingException("Failed to aquire Locl store handle " + e); + } + } + long end = System.currentTimeMillis(); + logger.info("Time taken to acquire lock store handle:" + (end - start) + " ms"); + return mLockHandle; + } + + /** + * + * @param remoteIp + * @return + */ + public static MusicDataStore getDSHandle(String remoteIp) { + logger.info("Acquiring data store handle"); + long start = System.currentTimeMillis(); + if (mDstoreHandle == null) { + mDstoreHandle = new MusicDataStore(remoteIp); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to acquire data store handle:" + (end - start) + " ms"); + return mDstoreHandle; + } + + /** + * + * @return + */ + public static MusicDataStore getDSHandle() { + logger.info("Acquiring data store handle"); + long start = System.currentTimeMillis(); + if (mDstoreHandle == null) { + mDstoreHandle = new MusicDataStore(); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to acquire data store handle:" + (end - start) + " ms"); + return mDstoreHandle; + } + + public static String createLockReference(String lockName) { + logger.info("Creating lock reference for lock name:" + lockName); + long start = System.currentTimeMillis(); + String lockId = null; + try { + lockId = getLockingServiceHandle().createLockId("/" + lockName); + } catch (MusicLockingException e) { + logger.error("Failed to create Lock Reference " + lockName); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to create lock reference:" + (end - start) + " ms"); + return lockId; + } + + /** + * + * @param key + * @return + */ + public static boolean isTableOrKeySpaceLock(String key) { + String[] splitString = key.split("\\."); + if (splitString.length > 2) + return false; + else + return true; + } + + /** + * + * @param key + * @return + */ + public static MusicLockState getMusicLockState(String key) { + long start = System.currentTimeMillis(); + try { + String[] splitString = key.split("\\."); + String keyspaceName = splitString[0]; + String tableName = splitString[1]; + String primaryKey = splitString[2]; + MusicLockState mls; + String lockName = keyspaceName + "." + tableName + "." + primaryKey; + mls = getLockingServiceHandle().getLockState(lockName); + long end = System.currentTimeMillis(); + logger.info("Time taken to get lock state:" + (end - start) + " ms"); + return mls; + } catch (NullPointerException | MusicLockingException e) { + logger.error("No lock object exists as of now.." + e); + } + return null; + } + + public static ReturnType acquireLockWithLease(String key, String lockId, long leasePeriod) { + try { + long start = System.currentTimeMillis(); + /* check if the current lock has exceeded its lease and if yes, release that lock */ + MusicLockState mls = getMusicLockState(key); + if (mls != null) { + if (mls.getLockStatus().equals(LockStatus.LOCKED)) { + logger.info("The current lock holder for " + key + " is " + mls.getLockHolder() + + ". Checking if it has exceeded lease"); + long currentLockPeriod = System.currentTimeMillis() - mls.getLeaseStartTime(); + long currentLeasePeriod = mls.getLeasePeriod(); + if (currentLockPeriod > currentLeasePeriod) { + logger.info("Lock period " + currentLockPeriod + + " has exceeded lease period " + currentLeasePeriod); + boolean voluntaryRelease = false; + String currentLockHolder = mls.getLockHolder(); + mls = releaseLock(currentLockHolder, voluntaryRelease); + } + } + } else + logger.debug("There is no lock state object for " + key); + + /* + * call the traditional acquire lock now and if the result returned is true, set the + * begin time-stamp and lease period + */ + if (acquireLock(key, lockId) == true) { + mls = getMusicLockState(key);// get latest state + if (mls.getLeaseStartTime() == -1) {// set it again only if it is not set already + mls.setLeaseStartTime(System.currentTimeMillis()); + mls.setLeasePeriod(leasePeriod); + getLockingServiceHandle().setLockState(key, mls); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to acquire leased lock:" + (end - start) + " ms"); + return new ReturnType(ResultType.SUCCESS, "Accquired lock"); + } else { + long end = System.currentTimeMillis(); + logger.info("Time taken to fail to acquire leased lock:" + (end - start) + " ms"); + return new ReturnType(ResultType.FAILURE, "Could not acquire lock"); + } + } catch (Exception e) { + StringWriter sw = new StringWriter(); + logger.error(e.getMessage()); + String exceptionAsString = sw.toString(); + return new ReturnType(ResultType.FAILURE, + "Exception thrown in acquireLockWithLease:\n" + exceptionAsString); + } + } + + public static boolean acquireLock(String key, String lockId) { + /* + * first check if I am on top. Since ids are not reusable there is no need to check + * lockStatus If the status is unlocked, then the above call will automatically return + * false. + */ + Boolean result = false; + try { + result = getLockingServiceHandle().isMyTurn(lockId); + } catch (MusicLockingException e2) { + logger.error("Failed to aquireLock lockId " + lockId + " " + e2); + } + if (result == false) { + logger.info("In acquire lock: Not your turn, someone else has the lock"); + return false; + } + + + // this is for backward compatibility where locks could also be acquired on just + // keyspaces or tables. + if (isTableOrKeySpaceLock(key) == true) { + logger.info("In acquire lock: A table or keyspace lock so no need to perform sync...so returning true"); + return true; + } + + // read the lock name corresponding to the key and if the status is locked or being locked, + // then return false + MusicLockState currentMls = null; + MusicLockState newMls = null; + try { + currentMls = getMusicLockState(key); + String currentLockHolder = currentMls.getLockHolder(); + if (lockId.equals(currentLockHolder)) { + logger.info("In acquire lock: You already have the lock!"); + return true; + } + } catch (NullPointerException e) { + logger.error("In acquire lock:No one has tried to acquire the lock yet.."); + } + + // change status to "being locked". This state transition is necessary to ensure syncing + // before granting the lock + String lockHolder = null; + boolean needToSyncQuorum = false; + if (currentMls != null) + needToSyncQuorum = currentMls.isNeedToSyncQuorum(); + + + newMls = new MusicLockState(MusicLockState.LockStatus.BEING_LOCKED, lockHolder, + needToSyncQuorum); + try { + getLockingServiceHandle().setLockState(key, newMls); + } catch (MusicLockingException e1) { + logger.error("Failed to set Lock state " + key + " " + e1); + } + logger.info("In acquire lock: Set lock state to being_locked"); + + // do syncing if this was a forced lock release + if (needToSyncQuorum) { + logger.info("In acquire lock: Since there was a forcible release, need to sync quorum!"); + syncQuorum(key); + } + + // change status to locked + lockHolder = lockId; + needToSyncQuorum = false; + newMls = new MusicLockState(MusicLockState.LockStatus.LOCKED, lockHolder, needToSyncQuorum); + try { + getLockingServiceHandle().setLockState(key, newMls); + } catch (MusicLockingException e) { + logger.error("Failed to set Lock state " + key + " " + e); + } + logger.info("In acquire lock: Set lock state to locked and assigned current lock ref " + + lockId + " as holder"); + return result; + } + + + + /** + * + * @param keyspaceName + * @param kspObject + * @return + * @throws Exception + */ + public boolean createKeyspace(String keyspaceName, JsonKeySpace kspObject) throws Exception { + return true; + } + + + private static void syncQuorum(String key) { + logger.info("Performing sync operation---"); + String[] splitString = key.split("\\."); + String keyspaceName = splitString[0]; + String tableName = splitString[1]; + String primaryKeyValue = splitString[2]; + PreparedQueryObject selectQuery = new PreparedQueryObject(); + PreparedQueryObject updateQuery = new PreparedQueryObject(); + + // get the primary key d + TableMetadata tableInfo = returnColumnMetadata(keyspaceName, tableName); + String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();// we only support single + // primary key + DataType primaryKeyType = tableInfo.getPrimaryKey().get(0).getType(); + String cqlFormattedPrimaryKeyValue = + MusicUtil.convertToCQLDataType(primaryKeyType, primaryKeyValue); + + // get the row of data from a quorum + selectQuery.appendQueryString("SELECT * FROM " + keyspaceName + "." + tableName + " WHERE " + + primaryKeyName + "= ?" + ";"); + selectQuery.addValue(cqlFormattedPrimaryKeyValue); + // String selectQuery = "SELECT * FROM "+keyspaceName+"."+tableName+ " WHERE + // "+primaryKeyName+"="+cqlFormattedPrimaryKeyValue+";"; + ResultSet results = null; + try { + results = getDSHandle().executeCriticalGet(selectQuery); + // write it back to a quorum + Row row = results.one(); + ColumnDefinitions colInfo = row.getColumnDefinitions(); + int totalColumns = colInfo.size(); + int counter = 1; + // String fieldValueString=""; + StringBuilder fieldValueString = new StringBuilder(""); + for (Definition definition : colInfo) { + String colName = definition.getName(); + if (colName.equals(primaryKeyName)) + continue; + DataType colType = definition.getType(); + Object valueObj = getDSHandle().getColValue(row, colName, colType); + String valueString = MusicUtil.convertToCQLDataType(colType, valueObj); + // fieldValueString = fieldValueString+ colName+"="+valueString; + fieldValueString.append(colName + " = ?"); + updateQuery.addValue(valueString); + if (counter != (totalColumns - 1)) + fieldValueString.append(","); + counter = counter + 1; + } + updateQuery.appendQueryString("UPDATE " + keyspaceName + "." + tableName + " SET " + + fieldValueString + " WHERE " + primaryKeyName + "= ? " + ";"); + updateQuery.addValue(cqlFormattedPrimaryKeyValue); + // String updateQuery = "UPDATE "+keyspaceName+"."+tableName+" SET "+fieldValueString+" + // WHERE "+primaryKeyName+"="+cqlFormattedPrimaryKeyValue+";"; + + getDSHandle().executePut(updateQuery, "critical"); + } catch (MusicServiceException | MusicQueryException e) { + logger.error("Failed to execute update query " + updateQuery + " " + e); + } + } + + + /** + * this function is mainly for the benchmarks to see the effect of lock deletion. + * + * @param keyspaceName + * @param tableName + * @param primaryKey + * @param queryObject + * @param conditionInfo + * @return + */ + public static ReturnType atomicPutWithDeleteLock(String keyspaceName, String tableName, + String primaryKey, PreparedQueryObject queryObject, Condition conditionInfo) { + long start = System.currentTimeMillis(); + String key = keyspaceName + "." + tableName + "." + primaryKey; + String lockId = createLockReference(key); + long lockCreationTime = System.currentTimeMillis(); + long leasePeriod = MusicUtil.getDefaultLockLeasePeriod(); + ReturnType lockAcqResult = acquireLockWithLease(key, lockId, leasePeriod); + long lockAcqTime = System.currentTimeMillis(); + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + logger.info("acquired lock with id " + lockId); + ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey, + queryObject, lockId, conditionInfo); + long criticalPutTime = System.currentTimeMillis(); + deleteLock(key); + long lockDeleteTime = System.currentTimeMillis(); + String timingInfo = "|lock creation time:" + (lockCreationTime - start) + + "|lock accquire time:" + (lockAcqTime - lockCreationTime) + + "|critical put time:" + (criticalPutTime - lockAcqTime) + + "|lock delete time:" + (lockDeleteTime - criticalPutTime) + "|"; + criticalPutResult.setTimingInfo(timingInfo); + return criticalPutResult; + } else { + logger.info("unable to acquire lock, id " + lockId); + deleteLock(key); + return lockAcqResult; + } + } + + /** + * + * @param query + * @return ResultSet + */ + public static ResultSet quorumGet(PreparedQueryObject query) { + ResultSet results = null; + try { + results = getDSHandle().executeCriticalGet(query); + } catch (MusicServiceException | MusicQueryException e) { + logger.error(e.getMessage()); + } + return results; + + } + + /** + * + * @param results + * @return + */ + public static Map> marshallResults(ResultSet results) { + return getDSHandle().marshalData(results); + } + + /** + * + * @param lockName + * @return + */ + public static String whoseTurnIsIt(String lockName) { + + try { + return getLockingServiceHandle().whoseTurnIsIt("/" + lockName) + ""; + } catch (MusicLockingException e) { + logger.error("Failed whoseTurnIsIt " + lockName + " " + e); + } + return null; + + + } + + /** + * + * @param lockId + * @return + */ + public static String getLockNameFromId(String lockId) { + StringTokenizer st = new StringTokenizer(lockId); + return st.nextToken("$"); + } + + public static void destroyLockRef(String lockId) { + long start = System.currentTimeMillis(); + try { + getLockingServiceHandle().unlockAndDeleteId(lockId); + } catch (MusicLockingException e) { + logger.error("Failed to Destroy Lock Ref " + lockId + " " + e); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to destroy lock reference:" + (end - start) + " ms"); + } + + public static MusicLockState releaseLock(String lockId, boolean voluntaryRelease) { + long start = System.currentTimeMillis(); + try { + getLockingServiceHandle().unlockAndDeleteId(lockId); + } catch (MusicLockingException e1) { + logger.error("Failed to release Lock " + lockId + " " + e1); + } + String lockName = getLockNameFromId(lockId); + MusicLockState mls; + String lockHolder = null; + if (voluntaryRelease) { + mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder); + logger.info("In unlock: lock voluntarily released for " + lockId); + } else { + boolean needToSyncQuorum = true; + mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder, + needToSyncQuorum); + logger.info("In unlock: lock forcibly released for " + lockId); + } + try { + getLockingServiceHandle().setLockState(lockName, mls); + } catch (MusicLockingException e) { + logger.error("Failed to release Lock " + lockName + " " + e); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to release lock:" + (end - start) + " ms"); + return mls; + } + + /** + * + * @param lockName + */ + public static void deleteLock(String lockName) { + long start = System.currentTimeMillis(); + logger.info("Deleting lock for " + lockName); + try { + getLockingServiceHandle().deleteLock("/" + lockName); + } catch (MusicLockingException e) { + logger.error("Failed to Delete Lock " + lockName + " " + e); + } + long end = System.currentTimeMillis(); + logger.info("Time taken to delete lock:" + (end - start) + " ms"); + } + + + + /** + * + * @param keyspace + * @param tablename + * @return + */ + public static TableMetadata returnColumnMetadata(String keyspace, String tablename) { + return getDSHandle().returnColumnMetadata(keyspace, tablename); + } + + + /** + * + * @param nodeName + */ + public static void pureZkCreate(String nodeName) { + try { + getLockingServiceHandle().getzkLockHandle().createNode(nodeName); + } catch (MusicLockingException e) { + logger.error("Failed to get ZK Lock Handle " + e); + } + } + + /** + * + * @param nodeName + * @param data + */ + public static void pureZkWrite(String nodeName, byte[] data) { + long start = System.currentTimeMillis(); + logger.info("Performing zookeeper write to " + nodeName); + try { + getLockingServiceHandle().getzkLockHandle().setNodeData(nodeName, data); + } catch (MusicLockingException e) { + logger.error("Failed to get ZK Lock Handle " + e); + } + logger.info("Performed zookeeper write to " + nodeName); + long end = System.currentTimeMillis(); + logger.info("Time taken for the actual zk put:" + (end - start) + " ms"); + } + + /** + * + * @param nodeName + * @return + */ + public static byte[] pureZkRead(String nodeName) { + long start = System.currentTimeMillis(); + byte[] data = null; + try { + data = getLockingServiceHandle().getzkLockHandle().getNodeData(nodeName); + } catch (MusicLockingException e) { + logger.error("Failed to get ZK Lock Handle " + e); + } + long end = System.currentTimeMillis(); + logger.info("Time taken for the actual zk put:" + (end - start) + " ms"); + return data; + } + + + + // Prepared Query Additions. + + /** + * + * @param keyspaceName + * @param tableName + * @param primaryKey + * @param queryObject + * @return ReturnType + * @throws MusicServiceException + */ + public static ReturnType eventualPut(PreparedQueryObject queryObject) { + boolean result = false; + try { + result = getDSHandle().executePut(queryObject, MusicUtil.EVENTUAL); + } catch (MusicServiceException | MusicQueryException ex) { + logger.error(ex.getMessage() + " " + ex.getCause() + " " + ex); + } + if (result) { + return new ReturnType(ResultType.SUCCESS, "Success"); + } else { + return new ReturnType(ResultType.FAILURE, "Failure"); + } + } + + /** + * + * @param keyspaceName + * @param tableName + * @param primaryKey + * @param queryObject + * @param lockId + * @return + */ + public static ReturnType criticalPut(String keyspaceName, String tableName, String primaryKey, + PreparedQueryObject queryObject, String lockId, Condition conditionInfo) { + long start = System.currentTimeMillis(); + + try { + MusicLockState mls = getLockingServiceHandle() + .getLockState(keyspaceName + "." + tableName + "." + primaryKey); + if (mls.getLockHolder().equals(lockId) == true) { + if (conditionInfo != null)// check if condition is true + if (conditionInfo.testCondition() == false) + return new ReturnType(ResultType.FAILURE, + "Lock acquired but the condition is not true"); + getDSHandle().executePut(queryObject, MusicUtil.CRITICAL); + long end = System.currentTimeMillis(); + logger.info("Time taken for the critical put:" + (end - start) + " ms"); + return new ReturnType(ResultType.SUCCESS, "Update performed"); + } else + return new ReturnType(ResultType.FAILURE, + "Cannot perform operation since you are the not the lock holder"); + } catch (MusicQueryException | MusicServiceException | MusicLockingException e) { + logger.error(e.getMessage()); + return new ReturnType(ResultType.FAILURE, + "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n" + + e.getMessage()); + } + + } + + /** + * + * @param queryObject + * @param consistency + * @return Boolean Indicates success or failure + * + * + */ + public static boolean nonKeyRelatedPut(PreparedQueryObject queryObject, String consistency) { + // this is mainly for some functions like keyspace creation etc which does not + // really need the bells and whistles of Music locking. + boolean result = false; + try { + result = getDSHandle().executePut(queryObject, consistency); + } catch (MusicQueryException | MusicServiceException ex) { + logger.error(ex.getMessage()); + } + return result; + } + + /** + * This method performs DDL operation on cassandra. + * + * @param queryObject query object containing prepared query and values + * @return ResultSet + */ + public static ResultSet get(PreparedQueryObject queryObject) { + ResultSet results = null; + try { + results = getDSHandle().executeEventualGet(queryObject); + } catch (MusicQueryException | MusicServiceException e) { + logger.error(e.getMessage()); + } + return results; + } + + /** + * This method performs DDL operations on cassandra, if the the resource is available. Lock ID + * is used to check if the resource is free. + * + * @param keyspaceName name of the keyspace + * @param tableName name of the table + * @param primaryKey primary key value + * @param queryObject query object containing prepared query and values + * @param lockId lock ID to check if the resource is free to perform the operation. + * @return ResultSet + */ + public static ResultSet criticalGet(String keyspaceName, String tableName, String primaryKey, + PreparedQueryObject queryObject, String lockId) throws MusicServiceException { + ResultSet results = null; + try { + MusicLockState mls = getLockingServiceHandle() + .getLockState(keyspaceName + "." + tableName + "." + primaryKey); + if (mls.getLockHolder().equals(lockId)) { + results = getDSHandle().executeCriticalGet(queryObject); + } else + throw new MusicServiceException("YOU DO NOT HAVE THE LOCK"); + } catch (MusicQueryException | MusicServiceException | MusicLockingException e) { + logger.error(e.getMessage()); + } + return results; + } + + /** + * This method performs DML operation on cassandra, when the lock of the dd is acquired. + * + * @param keyspaceName name of the keyspace + * @param tableName name of the table + * @param primaryKey primary key value + * @param queryObject query object containing prepared query and values + * @return ReturnType + */ + public static ReturnType atomicPut(String keyspaceName, String tableName, String primaryKey, + PreparedQueryObject queryObject, Condition conditionInfo) { + long start = System.currentTimeMillis(); + String key = keyspaceName + "." + tableName + "." + primaryKey; + String lockId = createLockReference(key); + long lockCreationTime = System.currentTimeMillis(); + long leasePeriod = MusicUtil.getDefaultLockLeasePeriod(); + ReturnType lockAcqResult = acquireLockWithLease(key, lockId, leasePeriod); + long lockAcqTime = System.currentTimeMillis(); + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + logger.info("acquired lock with id " + lockId); + ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey, + queryObject, lockId, conditionInfo); + long criticalPutTime = System.currentTimeMillis(); + boolean voluntaryRelease = true; + deleteLock(key); + long lockDeleteTime = System.currentTimeMillis(); + String timingInfo = "|lock creation time:" + (lockCreationTime - start) + + "|lock accquire time:" + (lockAcqTime - lockCreationTime) + + "|critical put time:" + (criticalPutTime - lockAcqTime) + + "|lock delete time:" + (lockDeleteTime - criticalPutTime) + "|"; + criticalPutResult.setTimingInfo(timingInfo); + return criticalPutResult; + } else { + logger.info("unable to acquire lock, id " + lockId); + destroyLockRef(lockId); + return lockAcqResult; + } + } + + + /** + * This method performs DDL operation on cassasndra, when the lock for the resource is acquired. + * + * @param keyspaceName name of the keyspace + * @param tableName name of the table + * @param primaryKey primary key value + * @param queryObject query object containing prepared query and values + * @return ResultSet + * @throws MusicServiceException + */ + public static ResultSet atomicGet(String keyspaceName, String tableName, String primaryKey, + PreparedQueryObject queryObject) throws MusicServiceException { + String key = keyspaceName + "." + tableName + "." + primaryKey; + String lockId = createLockReference(key); + long leasePeriod = MusicUtil.getDefaultLockLeasePeriod(); + ReturnType lockAcqResult = acquireLockWithLease(key, lockId, leasePeriod); + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + logger.info("acquired lock with id " + lockId); + ResultSet result = + criticalGet(keyspaceName, tableName, primaryKey, queryObject, lockId); + boolean voluntaryRelease = true; + releaseLock(lockId, voluntaryRelease); + return result; + } else { + logger.info("unable to acquire lock, id " + lockId); + return null; + } + } + + /** + * authenticate user logic + * + * @param nameSpace + * @param userId + * @param password + * @param keyspace + * @param aid + * @param operation + * @return + * @throws Exception + */ + public static Map autheticateUser(String nameSpace, String userId, + String password, String keyspace, String aid, String operation) + throws Exception { + Map resultMap = new HashMap<>(); + String uuid = null; + resultMap = CachingUtil.validateRequest(nameSpace, userId, password, keyspace, aid, + operation); + if (!resultMap.isEmpty()) + return resultMap; + if (aid == null && (userId == null || password == null)) { + logger.error("One or more required headers is missing. userId: " + userId + + " :: password: " + password); + resultMap.put("Exception", + "UserId and Password are mandatory for the operation " + operation); + return resultMap; + } + boolean isAAF = CachingUtil.isAAFApplication(nameSpace); + if (!isAAF && aid != null && aid.length() > 0) { // Non AAF app + resultMap = CachingUtil.authenticateAIDUser(aid, keyspace); + if (!resultMap.isEmpty()) + return resultMap; + } + if (isAAF && nameSpace != null && userId != null && password != null) { + boolean isValid = true; + try { + isValid = CachingUtil.authenticateAAFUser(nameSpace, userId, password, keyspace); + } catch (Exception e) { + logger.error("Got exception while AAF authentication for namespace " + nameSpace); + resultMap.put("Exception", e.getMessage()); + // return resultMap; + } + if (!isValid) { + logger.error("User not authenticated with AAF."); + resultMap.put("Exception", "User not authenticated..."); + // return resultMap; + } + if (!resultMap.isEmpty()) + return resultMap; + + } + + if (operation.equals("createKeySpace")) { + logger.info("AID is not provided. Creating new UUID for keyspace."); + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "select uuid from admin.keyspace_master where application_name=? and username=? and keyspace_name=? allow filtering"); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), nameSpace)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), + MusicUtil.DEFAULTKEYSPACENAME)); + + try { + Row rs = MusicCore.get(pQuery).one(); + uuid = rs.getUUID("uuid").toString(); + resultMap.put("uuid", "existing"); + } catch (Exception e) { + logger.info("No UUID found in DB. So creating new UUID."); + uuid = CachingUtil.generateUUID(); + resultMap.put("uuid", "new"); + } + + pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) values (?,?,?,?,?,?,?)"); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspace)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), nameSpace)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), password)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + CachingUtil.updateMusicCache(uuid, keyspace); + MusicCore.eventualPut(pQuery); + resultMap.put("aid", uuid); + } + + return resultMap; + } +} diff --git a/src/main/java/org/onap/music/main/MusicDigest.java b/src/main/java/org/onap/music/main/MusicDigest.java new file mode 100644 index 00000000..893cb51f --- /dev/null +++ b/src/main/java/org/onap/music/main/MusicDigest.java @@ -0,0 +1,78 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + +/** + * + * + */ +public class MusicDigest { + private String evPutStatus; + private String vectorTs; + + /** + * @param evPutStatus + * @param vectorTs + */ + public MusicDigest(String evPutStatus, String vectorTs) { + this.evPutStatus = evPutStatus; + this.vectorTs = vectorTs; + } + + /** + * @return + */ + public String getEvPutStatus() { + return evPutStatus; + } + + /** + * @param evPutStatus + */ + public void setEvPutStatus(String evPutStatus) { + this.evPutStatus = evPutStatus; + } + + /** + * @return + */ + public String getVectorTs() { + return vectorTs; + } + + /** + * @param vectorTs + */ + public void setVectorTs(String vectorTs) { + this.vectorTs = vectorTs; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + return vectorTs + "|" + evPutStatus; + } +} + diff --git a/src/main/java/org/onap/music/main/MusicUtil.java b/src/main/java/org/onap/music/main/MusicUtil.java new file mode 100755 index 00000000..61d428d1 --- /dev/null +++ b/src/main/java/org/onap/music/main/MusicUtil.java @@ -0,0 +1,465 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + + +import java.io.File; +import java.io.FileNotFoundException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.UUID; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import com.datastax.driver.core.DataType; + +/** + * @author nelson24 + * + * Properties This will take Properties and load them into MusicUtil. This is a hack for + * now. Eventually it would bebest to do this in another way. + * + */ +public class MusicUtil { + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicUtil.class); + + private static int myId = 0; + private static ArrayList allIds = new ArrayList(); + private static String publicIp = ""; + private static ArrayList allPublicIps = new ArrayList(); + private static String myZkHost = "localhost"; + private static String myCassaHost = "localhost"; + private static String defaultMusicIp = "localhost"; + private static boolean debug = true; + private static String version = "2.3.0"; + public static String musicRestIp = "localhost"; + private static String musicPropertiesFilePath = "/opt/app/music/etc/music.properties"; + private static long defaultLockLeasePeriod = 6000; + private static final String[] propKeys = new String[] {"zookeeper.host", "cassandra.host", + "music.ip", "debug", "version", "music.rest.ip", "music.properties", + "lock.lease.period", "id", "all.ids", "public.ip", "all.pubic.ips", + "cassandra.user", "cassandra.password", "aaf.endpoint.url"}; + + public static final String ATOMIC = "atomic"; + public static final String EVENTUAL = "eventual"; + public static final String CRITICAL = "critical"; + public static final String DEFAULTKEYSPACENAME = "TBD"; + private static String cassName = "cassandra"; + private static String cassPwd = "cassandra"; + private static String aafEndpointUrl = null; + + /** + * @return the cassName + */ + public static String getCassName() { + return cassName; + } + + /** + * @return the cassPwd + */ + public static String getCassPwd() { + return cassPwd; + } + + /** + * @return the aafEndpointUrl + */ + public static String getAafEndpointUrl() { + return aafEndpointUrl; + } + + /** + * + * @param aafEndpointUrl + */ + public static void setAafEndpointUrl(String aafEndpointUrl) { + MusicUtil.aafEndpointUrl = aafEndpointUrl; + } + + /** + * + * @return + */ + public static int getMyId() { + return myId; + } + + /** + * + * @param myId + */ + public static void setMyId(int myId) { + MusicUtil.myId = myId; + } + + + /** + * + * @return + */ + public static ArrayList getAllIds() { + return allIds; + } + + /** + * + * @param allIds + */ + public static void setAllIds(List allIds) { + MusicUtil.allIds = (ArrayList) allIds; + } + + /** + * + * @return + */ + public static String getPublicIp() { + return publicIp; + } + + /** + * + * @param publicIp + */ + public static void setPublicIp(String publicIp) { + MusicUtil.publicIp = publicIp; + } + + /** + * + * @return + */ + public static ArrayList getAllPublicIps() { + return allPublicIps; + } + + /** + * + * @param allPublicIps + */ + public static void setAllPublicIps(List allPublicIps) { + MusicUtil.allPublicIps = (ArrayList) allPublicIps; + } + + /** + * Returns An array of property names that should be in the Properties files. + * + * @return + */ + public static String[] getPropkeys() { + return propKeys; + } + + /** + * Get MusicRestIp - default = localhost property file value - music.rest.ip + * + * @return + */ + public static String getMusicRestIp() { + return musicRestIp; + } + + /** + * Set MusicRestIp + * + * @param musicRestIp + */ + public static void setMusicRestIp(String musicRestIp) { + MusicUtil.musicRestIp = musicRestIp; + } + + /** + * Get MusicPropertiesFilePath - Default = /opt/music/music.properties property file value - + * music.properties + * + * @return + */ + public static String getMusicPropertiesFilePath() { + return musicPropertiesFilePath; + } + + /** + * Set MusicPropertiesFilePath + * + * @param musicPropertiesFilePath + */ + public static void setMusicPropertiesFilePath(String musicPropertiesFilePath) { + MusicUtil.musicPropertiesFilePath = musicPropertiesFilePath; + } + + /** + * Get DefaultLockLeasePeriod - Default = 6000 property file value - lock.lease.period + * + * @return + */ + public static long getDefaultLockLeasePeriod() { + return defaultLockLeasePeriod; + } + + /** + * Set DefaultLockLeasePeriod + * + * @param defaultLockLeasePeriod + */ + public static void setDefaultLockLeasePeriod(long defaultLockLeasePeriod) { + MusicUtil.defaultLockLeasePeriod = defaultLockLeasePeriod; + } + + /** + * Set Debug + * + * @param debug + */ + public static void setDebug(boolean debug) { + MusicUtil.debug = debug; + } + + /** + * Is Debug - Default = true property file value - debug + * + * @return + */ + public static boolean isDebug() { + return debug; + } + + /** + * Set Version + * + * @param version + */ + public static void setVersion(String version) { + MusicUtil.version = version; + } + + /** + * Return the version property file value - version + * + * @return + */ + public static String getVersion() { + return version; + } + + /** + * Get MyZkHost - Zookeeper Hostname - Default = localhost property file value - zookeeper.host + * + * @return + */ + public static String getMyZkHost() { + return myZkHost; + } + + /** + * Set MyZkHost - Zookeeper Hostname + * + * @param myZkHost + */ + public static void setMyZkHost(String myZkHost) { + MusicUtil.myZkHost = myZkHost; + } + + /** + * Get MyCassHost - Cassandra Hostname - Default = localhost property file value - + * cassandra.host + * + * @return + */ + public static String getMyCassaHost() { + return myCassaHost; + } + + /** + * Set MyCassHost - Cassandra Hostname + * + * @param myCassaHost + */ + public static void setMyCassaHost(String myCassaHost) { + MusicUtil.myCassaHost = myCassaHost; + } + + /** + * Get DefaultMusicIp - Default = localhost property file value - music.ip + * + * @return + */ + public static String getDefaultMusicIp() { + return defaultMusicIp; + } + + /** + * Set DefaultMusicIp + * + * @param defaultMusicIp + */ + public static void setDefaultMusicIp(String defaultMusicIp) { + MusicUtil.defaultMusicIp = defaultMusicIp; + } + + /** + * + * @return + */ + public static String getTestType() { + String testType = ""; + try { + Scanner fileScanner = new Scanner(new File("")); + testType = fileScanner.next();// ignore the my id line + String batchSize = fileScanner.next();// ignore the my public ip line + fileScanner.close(); + } catch (FileNotFoundException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage()); + } + return testType; + + } + + /** + * + * @param time + */ + public static void sleep(long time) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage()); + } + } + + /** + * Utility function to check if the query object is valid. + * + * @param withparams + * @param queryObject + * @return + */ + public static boolean isValidQueryObject(boolean withparams, PreparedQueryObject queryObject) { + if (withparams) { + int noOfValues = queryObject.getValues().size(); + int noOfParams = 0; + char[] temp = queryObject.getQuery().toCharArray(); + for (int i = 0; i < temp.length; i++) { + if (temp[i] == '?') + noOfParams++; + } + return (noOfValues == noOfParams); + } else { + return !queryObject.getQuery().isEmpty(); + } + + } + + public static void setCassName(String cassName) { + MusicUtil.cassName = cassName; + } + + public static void setCassPwd(String cassPwd) { + MusicUtil.cassPwd = cassPwd; + } + + public static String convertToCQLDataType(DataType type, Object valueObj) { + + String value = ""; + switch (type.getName()) { + case UUID: + value = valueObj + ""; + break; + case TEXT: + case VARCHAR: + String valueString = valueObj + ""; + valueString = valueString.replace("'", "''"); + value = "'" + valueString + "'"; + break; + case MAP: { + Map otMap = (Map) valueObj; + value = "{" + jsonMaptoSqlString(otMap, ",") + "}"; + break; + } + default: + value = valueObj + ""; + break; + } + return value; + } + + + /** + * + * @param colType + * @param valueObj + * @return + * @throws Exception + */ + public static Object convertToActualDataType(DataType colType, Object valueObj) { + String valueObjString = valueObj + ""; + switch (colType.getName()) { + case UUID: + return UUID.fromString(valueObjString); + case VARINT: + return BigInteger.valueOf(Long.parseLong(valueObjString)); + case BIGINT: + return Long.parseLong(valueObjString); + case INT: + return Integer.parseInt(valueObjString); + case FLOAT: + return Float.parseFloat(valueObjString); + case DOUBLE: + return Double.parseDouble(valueObjString); + case BOOLEAN: + return Boolean.parseBoolean(valueObjString); + case MAP: + return (Map) valueObj; + default: + return valueObjString; + } + } + + + /** + * + * Utility function to parse json map into sql like string + * + * @param jMap + * @param lineDelimiter + * @return + */ + + public static String jsonMaptoSqlString(Map jMap, String lineDelimiter) { + StringBuilder sqlString = new StringBuilder(); + int counter = 0; + for (Map.Entry entry : jMap.entrySet()) { + Object ot = entry.getValue(); + String value = ot + ""; + if (ot instanceof String) { + value = "'" + value.replace("'", "''") + "'"; + } + sqlString.append("'" + entry.getKey() + "':" + value); + if (counter != jMap.size() - 1) + sqlString.append(lineDelimiter); + counter = counter + 1; + } + return sqlString.toString(); + } +} diff --git a/src/main/java/org/onap/music/main/PropertiesListener.java b/src/main/java/org/onap/music/main/PropertiesListener.java new file mode 100755 index 00000000..de231542 --- /dev/null +++ b/src/main/java/org/onap/music/main/PropertiesListener.java @@ -0,0 +1,147 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Properties; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; +import org.onap.music.eelf.logging.EELFLoggerDelegate; + +@WebListener +public class PropertiesListener implements ServletContextListener { + private Properties prop; + + private static EELFLoggerDelegate logger = + EELFLoggerDelegate.getLogger(PropertiesListener.class); + + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + prop = new Properties(); + Properties projectProp = new Properties(); + URL resource = getClass().getResource("/"); + String musicPropertiesFilePath = resource.getPath().replace("WEB-INF/classes/", + "WEB-INF/classes/project.properties"); + + // Open the file + try { + InputStream musicProps = null; + projectProp.load(new FileInputStream(musicPropertiesFilePath)); + if (projectProp.containsKey("music.properties")) { + musicProps = new FileInputStream(projectProp.getProperty("music.properties")); + } else { + musicProps = new FileInputStream(MusicUtil.getMusicPropertiesFilePath()); + } + prop.load(musicProps); + musicProps.close(); + prop.putAll(projectProp); + String[] propKeys = MusicUtil.getPropkeys(); + for (int k = 0; k < propKeys.length; k++) { + String key = propKeys[k]; + if (prop.containsKey(key) && prop.get(key) != null) { + logger.info(key + " : " + prop.getProperty(key)); + switch (key) { + case "zookeeper.host": + MusicUtil.setMyZkHost(prop.getProperty(key)); + break; + case "cassandra.host": + MusicUtil.setMyCassaHost(prop.getProperty(key)); + break; + case "music.ip": + MusicUtil.setDefaultMusicIp(prop.getProperty(key)); + break; + case "debug": + MusicUtil.setDebug(Boolean + .getBoolean(prop.getProperty(key).toLowerCase())); + break; + case "version": + MusicUtil.setVersion(prop.getProperty(key)); + break; + case "music.rest.ip": + MusicUtil.setMusicRestIp(prop.getProperty(key)); + break; + case "music.properties": + MusicUtil.setMusicPropertiesFilePath(prop.getProperty(key)); + break; + case "lock.lease.period": + MusicUtil.setDefaultLockLeasePeriod( + Long.parseLong(prop.getProperty(key))); + break; + case "my.id": + MusicUtil.setMyId(Integer.parseInt(prop.getProperty(key))); + break; + case "all.ids": + String[] ids = prop.getProperty(key).split(":"); + MusicUtil.setAllIds(new ArrayList(Arrays.asList(ids))); + break; + case "public.ip": + MusicUtil.setPublicIp(prop.getProperty(key)); + break; + case "all.public.ips": + String[] ips = prop.getProperty(key).split(":"); + if (ips.length == 1) { + // Future use + } else if (ips.length > 1) { + MusicUtil.setAllPublicIps( + new ArrayList(Arrays.asList(ips))); + } + break; + case "cassandra.user": + MusicUtil.setCassName(prop.getProperty(key)); + break; + case "cassandra.password": + MusicUtil.setCassPwd(prop.getProperty(key)); + break; + case "aaf.endpoint.url": + MusicUtil.setAafEndpointUrl(prop.getProperty(key)); + break; + default: + logger.error(EELFLoggerDelegate.errorLogger, + "No case found for " + key); + } + } + } + } catch (IOException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage()); + } + + logger.info(EELFLoggerDelegate.applicationLogger, + "Starting MUSIC " + MusicUtil.getVersion() + " on node with id " + + MusicUtil.getMyId() + " and public ip " + + MusicUtil.getPublicIp() + "..."); + logger.info(EELFLoggerDelegate.applicationLogger, + "List of all MUSIC ids:" + MusicUtil.getAllIds().toString()); + logger.info(EELFLoggerDelegate.applicationLogger, + "List of all MUSIC public ips:" + MusicUtil.getAllPublicIps().toString()); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + prop = null; + } +} diff --git a/src/main/java/org/onap/music/main/ResultType.java b/src/main/java/org/onap/music/main/ResultType.java new file mode 100644 index 00000000..f19ada4a --- /dev/null +++ b/src/main/java/org/onap/music/main/ResultType.java @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + +public enum ResultType { + SUCCESS("Success"), FAILURE("Failure"); + + private String result; + + ResultType(String result) { + this.result = result; + } + + public String getResult() { + return result; + } + +} + + diff --git a/src/main/java/org/onap/music/main/ReturnType.java b/src/main/java/org/onap/music/main/ReturnType.java new file mode 100644 index 00000000..1453a1bf --- /dev/null +++ b/src/main/java/org/onap/music/main/ReturnType.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.main; + +import java.util.HashMap; +import java.util.Map; + +public class ReturnType { + private ResultType result; + private String message; + + public ReturnType(ResultType result, String message) { + super(); + this.result = result; + this.message = message; + } + + public String getTimingInfo() { + return timingInfo; + } + + public void setTimingInfo(String timingInfo) { + this.timingInfo = timingInfo; + } + + private String timingInfo; + + public ResultType getResult() { + return result; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String toJson() { + return "{ \"result\":\"" + result.getResult() + "\", \"message\":\"" + message + "\"}"; + } + + public String toString() { + return result + " | " + message; + } + + public Map toMap() { + Map newMap = new HashMap<>(); + newMap.put("result", result.getResult()); + newMap.put("message", message); + return newMap; + } + +} -- cgit 1.2.3-korg