diff options
Diffstat (limited to 'music-core/src/main/java/org/onap/music/datastore')
14 files changed, 3054 insertions, 0 deletions
diff --git a/music-core/src/main/java/org/onap/music/datastore/Condition.java b/music-core/src/main/java/org/onap/music/datastore/Condition.java new file mode 100644 index 00000000..c17d9c07 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/Condition.java @@ -0,0 +1,63 @@ +/* + * ============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.datastore; + +import java.util.Map; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + +public class Condition { + private Map<String, Object> conditions; + private PreparedQueryObject selectQueryForTheRow; + + public Condition(Map<String, Object> conditions, PreparedQueryObject selectQueryForTheRow) { + this.conditions = conditions; + this.selectQueryForTheRow = selectQueryForTheRow; + } + + public boolean testCondition() throws Exception { + // first generate the row + ResultSet results = quorumGet(selectQueryForTheRow); + Row row = null; + if(results != null) { + row = results.one(); + } + if(row == null) { + throw new Exception(" No data found to update"); + } + return getDSHandle().doesRowSatisfyCondition(row, conditions); + } + + /* For JUnit testing only */ + public ResultSet quorumGet(PreparedQueryObject selectQueryForTheRow) { + return MusicCore.quorumGet(selectQueryForTheRow); + } + + /* For JUnit testing only */ + public MusicDataStore getDSHandle() throws MusicServiceException { + return MusicDataStoreHandle.getDSHandle(); + } + }
\ No newline at end of file diff --git a/music-core/src/main/java/org/onap/music/datastore/MusicDataStore.java b/music-core/src/main/java/org/onap/music/datastore/MusicDataStore.java new file mode 100755 index 00000000..9ce73cc8 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/MusicDataStore.java @@ -0,0 +1,540 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2018-2019 IBM + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * 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.datastore; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.lockingservice.cassandra.LockType; +import org.onap.music.main.CipherUtil; +import org.onap.music.main.MusicUtil; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ColumnDefinitions; +import com.datastax.driver.core.ColumnDefinitions.Definition; +import com.datastax.driver.core.ConsistencyLevel; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.HostDistance; +import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.driver.core.Metadata; +import com.datastax.driver.core.PoolingOptions; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.SocketOptions; +import com.datastax.driver.core.TableMetadata; +import com.datastax.driver.core.exceptions.AlreadyExistsException; +import com.datastax.driver.core.exceptions.InvalidQueryException; +import com.datastax.driver.extras.codecs.enums.EnumNameCodec; + +/** + * @author nelson24 + * + */ +public class MusicDataStore { + + public static final String CONSISTENCY_LEVEL_ONE = "ONE"; + public static final String CONSISTENCY_LEVEL_QUORUM = "QUORUM"; + public static final String CONSISTENCY_LEVEL_LOCAL_QUORUM = "LOCAL_QUORUM"; + private Session session; + private Cluster cluster; + + + /** + * Connect to default Cassandra address + */ + public MusicDataStore() { + try { + connectToCassaCluster(MusicUtil.getMyCassaHost()); + } catch (MusicServiceException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e); + } + } + + + /** + * @param cluster + * @param session + */ + public MusicDataStore(Cluster cluster, Session session) { + this.session = session; + setCluster(cluster); + } + + + /** + * @param session + */ + public void setSession(Session session) { + this.session = session; + } + + /** + * @param session + */ + public Session getSession() { + return session; + } + + /** + * @param cluster + */ + public void setCluster(Cluster cluster) { + EnumNameCodec<LockType> lockTypeCodec = new EnumNameCodec<LockType>(LockType.class); + cluster.getConfiguration().getCodecRegistry().register(lockTypeCodec); + + this.cluster = cluster; + } + + public Cluster getCluster() { + return this.cluster; + } + + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicDataStore.class); + + + /** + * + * @param remoteIp + * @throws MusicServiceException + */ + public MusicDataStore(String remoteIp) { + try { + connectToCassaCluster(remoteIp); + } catch (MusicServiceException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e); + } + } + + /** + * + */ + public void close() { + session.close(); + } + + /** + * This method connects to cassandra cluster on specific address. + * + * @param address + */ + private void connectToCassaCluster(String address) throws MusicServiceException { + String[] addresses = null; + addresses = address.split(","); + PoolingOptions poolingOptions = new PoolingOptions(); + poolingOptions + .setConnectionsPerHost(HostDistance.LOCAL, 4, 10) + .setConnectionsPerHost(HostDistance.REMOTE, 2, 4); + + Cluster cluster; + if(MusicUtil.getCassName() != null && MusicUtil.getCassPwd() != null) { + String cassPwd; + if (MusicUtil.getCipherEncKey() != null && !("").equals(MusicUtil.getCipherEncKey())) { + cassPwd = CipherUtil.decryptPKC(MusicUtil.getCassPwd()); + } else { + cassPwd = MusicUtil.getCassPwd(); + } + logger.info(EELFLoggerDelegate.applicationLogger, + "Building with credentials "+MusicUtil.getCassName()+" & "+ MusicUtil.getCassPwd()); + cluster = Cluster.builder().withPort(MusicUtil.getCassandraPort()) + .withCredentials(MusicUtil.getCassName(), cassPwd) + //.withLoadBalancingPolicy(new RoundRobinPolicy()) + .withoutJMXReporting() + .withPoolingOptions(poolingOptions) + .withSocketOptions( + new SocketOptions().setConnectTimeoutMillis(MusicUtil.getCassandraConnectTimeOutMS()) + .setReadTimeoutMillis(MusicUtil.getCassandraReadTimeOutMS())) + .addContactPoints(addresses).build(); + } else { + cluster = Cluster.builder().withPort(MusicUtil.getCassandraPort()) + .withoutJMXReporting() + .withPoolingOptions(poolingOptions) + .withSocketOptions(new SocketOptions() + .setConnectTimeoutMillis(MusicUtil.getCassandraConnectTimeOutMS()) + .setReadTimeoutMillis(MusicUtil.getCassandraReadTimeOutMS())) + .addContactPoints(addresses) + .build(); + } + + this.setCluster(cluster); + Metadata metadata = this.cluster.getMetadata(); + logger.info(EELFLoggerDelegate.applicationLogger, "Connected to cassa cluster " + + metadata.getClusterName() + " at " + address); + + try { + session = this.cluster.connect(); + } catch (Exception ex) { + logger.error(EELFLoggerDelegate.errorLogger, ex.getMessage(),AppMessages.CASSANDRACONNECTIVITY, + ErrorSeverity.ERROR, ErrorTypes.SERVICEUNAVAILABLE, ex); + throw new MusicServiceException( + "Error while connecting to Cassandra cluster.. " + ex.getMessage()); + } + } + + /** + * + * @param keyspace + * @param tableName + * @param columnName + * @return DataType + */ + public DataType returnColumnDataType(String keyspace, String tableName, String columnName) { + KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(keyspace); + TableMetadata table = ks.getTable(tableName); + return table.getColumn(columnName).getType(); + + } + + /** + * + * @param keyspace + * @param tableName + * @return TableMetadata + */ + public TableMetadata returnColumnMetadata(String keyspace, String tableName) { + KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(keyspace); + return ks.getTable(tableName); + } + + /** + * + * @param keyspace + * @param tableName + * @return TableMetadata + */ + public KeyspaceMetadata returnKeyspaceMetadata(String keyspace) { + return cluster.getMetadata().getKeyspace(keyspace); + } + + + /** + * Utility function to return the Java specific object type. + * + * @param row + * @param colName + * @param colType + * @return + */ + public Object getColValue(Row row, String colName, DataType colType) { + + switch (colType.getName()) { + case VARCHAR: + return row.getString(colName); + case UUID: + return row.getUUID(colName); + case VARINT: + return row.getVarint(colName); + case BIGINT: + return row.getLong(colName); + case INT: + return row.getInt(colName); + case FLOAT: + return row.getFloat(colName); + case DOUBLE: + return row.getDouble(colName); + case BOOLEAN: + return row.getBool(colName); + case MAP: + return row.getMap(colName, String.class, String.class); + case LIST: + return row.getList(colName, String.class); + default: + return null; + } + } + + public byte[] getBlobValue(Row row, String colName, DataType colType) { + ByteBuffer bb = row.getBytes(colName); + return bb.array(); + } + + public boolean doesRowSatisfyCondition(Row row, Map<String, Object> condition) throws Exception { + ColumnDefinitions colInfo = row.getColumnDefinitions(); + + for (Map.Entry<String, Object> entry : condition.entrySet()) { + String colName = entry.getKey(); + DataType colType = colInfo.getType(colName); + Object columnValue = getColValue(row, colName, colType); + Object conditionValue = MusicUtil.convertToActualDataType(colType, entry.getValue()); + if (columnValue.equals(conditionValue) == false) + return false; + } + return true; + } + + /** + * Utility function to store ResultSet values in to a MAP for output. + * + * @param results + * @return MAP + */ + public Map<String, HashMap<String, Object>> marshalData(ResultSet results) { + Map<String, HashMap<String, Object>> resultMap = + new HashMap<>(); + int counter = 0; + for (Row row : results) { + ColumnDefinitions colInfo = row.getColumnDefinitions(); + HashMap<String, Object> resultOutput = new HashMap<>(); + for (Definition definition : colInfo) { + if (!(("vector_ts").equals(definition.getName()))) { + if(definition.getType().toString().toLowerCase().contains("blob")) { + resultOutput.put(definition.getName(), + getBlobValue(row, definition.getName(), definition.getType())); + } else { + resultOutput.put(definition.getName(), + getColValue(row, definition.getName(), definition.getType())); + } + } + } + resultMap.put("row " + counter, resultOutput); + counter++; + } + return resultMap; + } + + + // Prepared Statements 1802 additions + + public boolean executePut(PreparedQueryObject queryObject, String consistency) + throws MusicServiceException, MusicQueryException { + return executePut(queryObject, consistency, 0); + } + /** + * This Method performs DDL and DML operations on Cassandra using specified consistency level + * + * @param queryObject Object containing cassandra prepared query and values. + * @param consistency Specify consistency level for data synchronization across cassandra + * replicas + * @return Boolean Indicates operation success or failure + * @throws MusicServiceException + * @throws MusicQueryException + */ + public boolean executePut(PreparedQueryObject queryObject, String consistency,long timeSlot) + throws MusicServiceException, MusicQueryException { + + boolean result = false; + long timeOfWrite = System.currentTimeMillis(); + if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) { + logger.error(EELFLoggerDelegate.errorLogger, queryObject.getQuery(),AppMessages.QUERYERROR, ErrorSeverity.ERROR, ErrorTypes.QUERYERROR); + throw new MusicQueryException("Ill formed queryObject for the request = " + "[" + + queryObject.getQuery() + "]"); + } + logger.debug(EELFLoggerDelegate.applicationLogger, + "In preprared Execute Put: the actual insert query:" + + queryObject.getQuery() + "; the values" + + queryObject.getValues()); + SimpleStatement preparedInsert = null; + + try { + preparedInsert = new SimpleStatement(queryObject.getQuery(), queryObject.getValues().toArray()); + if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) { + logger.info(EELFLoggerDelegate.applicationLogger, "Executing critical put query"); + preparedInsert.setConsistencyLevel(ConsistencyLevel.QUORUM); + } else if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) { + logger.info(EELFLoggerDelegate.applicationLogger, "Executing simple put query"); + if(queryObject.getConsistency() == null) + preparedInsert.setConsistencyLevel(ConsistencyLevel.ONE); + else + preparedInsert.setConsistencyLevel(MusicUtil.getConsistencyLevel(queryObject.getConsistency())); + } else if (consistency.equalsIgnoreCase(MusicUtil.ONE)) { + preparedInsert.setConsistencyLevel(ConsistencyLevel.ONE); + } else if (consistency.equalsIgnoreCase(MusicUtil.QUORUM)) { + preparedInsert.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); + } else if (consistency.equalsIgnoreCase(MusicUtil.ALL)) { + preparedInsert.setConsistencyLevel(ConsistencyLevel.ALL); + } + long timestamp = MusicUtil.v2sTimeStampInMicroseconds(timeSlot, timeOfWrite); + preparedInsert.setDefaultTimestamp(timestamp); + + ResultSet rs = session.execute(preparedInsert); + result = rs.wasApplied(); + } catch (AlreadyExistsException ae) { + throw new MusicServiceException("Already Exists Exception: " + ae.getMessage()); + } catch (InvalidQueryException e) { + if (e.getMessage().contains("unconfigured table")) { + throw new MusicServiceException("Invalid Query Exception: " + e.getMessage()); + } else { + logger.info(EELFLoggerDelegate.applicationLogger, "Query Exception: " + e.getMessage(), + AppMessages.SESSIONFAILED + " [" + queryObject.getQuery() + "]", ErrorSeverity.INFO, + ErrorTypes.QUERYERROR, e); + throw new MusicServiceException("Query Exception: " + e.getMessage()); + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), + AppMessages.SESSIONFAILED + " [" + queryObject.getQuery() + "]", ErrorSeverity.ERROR, + ErrorTypes.QUERYERROR, e); + throw new MusicServiceException("Executing Session Failure for Request = " + "[" + queryObject.getQuery() + + "]" + " Reason = " + e.getMessage()); + } + + return result; + } + + /* *//** + * This method performs DDL operations on Cassandra using consistency level ONE. + * + * @param queryObject Object containing cassandra prepared query and values. + * @return ResultSet + * @throws MusicServiceException + * @throws MusicQueryException + *//* + public ResultSet executeEventualGet(PreparedQueryObject queryObject) + throws MusicServiceException, MusicQueryException { + CacheAccess<String, PreparedStatement> queryBank = CachingUtil.getStatementBank(); + PreparedStatement preparedEventualGet = null; + if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) { + logger.error(EELFLoggerDelegate.errorLogger, "",AppMessages.QUERYERROR+ " [" + queryObject.getQuery() + "]", ErrorSeverity.ERROR, ErrorTypes.QUERYERROR); + throw new MusicQueryException("Ill formed queryObject for the request = " + "[" + + queryObject.getQuery() + "]"); + } + logger.info(EELFLoggerDelegate.applicationLogger, + "Executing Eventual get query:" + queryObject.getQuery()); + + ResultSet results = null; + try { + if(queryBank.get(queryObject.getQuery()) != null ) + preparedEventualGet=queryBank.get(queryObject.getQuery()); + else { + preparedEventualGet = session.prepare(queryObject.getQuery()); + CachingUtil.updateStatementBank(queryObject.getQuery(), preparedEventualGet); + } + if(queryObject.getConsistency() == null) { + preparedEventualGet.setConsistencyLevel(ConsistencyLevel.ONE); + } else { + preparedEventualGet.setConsistencyLevel(MusicUtil.getConsistencyLevel(queryObject.getConsistency())); + } + results = session.execute(preparedEventualGet.bind(queryObject.getValues().toArray())); + + } catch (Exception ex) { + logger.error("Exception", ex); + logger.error(EELFLoggerDelegate.errorLogger, ex.getMessage(),AppMessages.UNKNOWNERROR+ "[" + queryObject.getQuery() + "]", ErrorSeverity.ERROR, ErrorTypes.QUERYERROR); + throw new MusicServiceException(ex.getMessage()); + } + return results; + } + + *//** + * + * This method performs DDL operation on Cassandra using consistency level QUORUM. + * + * @param queryObject Object containing cassandra prepared query and values. + * @return ResultSet + * @throws MusicServiceException + * @throws MusicQueryException + *//* + public ResultSet executeCriticalGet(PreparedQueryObject queryObject) + throws MusicServiceException, MusicQueryException { + if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) { + logger.error(EELFLoggerDelegate.errorLogger, "",AppMessages.QUERYERROR+ " [" + queryObject.getQuery() + "]", ErrorSeverity.ERROR, ErrorTypes.QUERYERROR); + throw new MusicQueryException("Error processing Prepared Query Object for the request = " + "[" + + queryObject.getQuery() + "]"); + } + logger.info(EELFLoggerDelegate.applicationLogger, + "Executing Critical get query:" + queryObject.getQuery()); + PreparedStatement preparedEventualGet = session.prepare(queryObject.getQuery()); + preparedEventualGet.setConsistencyLevel(ConsistencyLevel.QUORUM); + ResultSet results = null; + try { + results = session.execute(preparedEventualGet.bind(queryObject.getValues().toArray())); + } catch (Exception ex) { + logger.error("Exception", ex); + logger.error(EELFLoggerDelegate.errorLogger, ex.getMessage(),AppMessages.UNKNOWNERROR+ "[" + queryObject.getQuery() + "]", ErrorSeverity.ERROR, ErrorTypes.QUERYERROR); + throw new MusicServiceException(ex.getMessage()); + } + return results; + + } + */ + public ResultSet executeGet(PreparedQueryObject queryObject,String consistencyLevel) throws MusicQueryException, MusicServiceException { + if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) { + logger.error(EELFLoggerDelegate.errorLogger, "",AppMessages.QUERYERROR+ " [" + queryObject.getQuery() + "]", ErrorSeverity.ERROR, ErrorTypes.QUERYERROR); + throw new MusicQueryException("Error processing Prepared Query Object for the request = " + "[" + + queryObject.getQuery() + "]"); + } + ResultSet results = null; + try { + SimpleStatement statement = new SimpleStatement(queryObject.getQuery(), queryObject.getValues().toArray()); + if (consistencyLevel.equalsIgnoreCase(CONSISTENCY_LEVEL_ONE)) { + statement.setConsistencyLevel(ConsistencyLevel.ONE); + } else if (consistencyLevel.equalsIgnoreCase(CONSISTENCY_LEVEL_QUORUM)) { + statement.setConsistencyLevel(ConsistencyLevel.QUORUM); + } else if (consistencyLevel.equalsIgnoreCase(CONSISTENCY_LEVEL_LOCAL_QUORUM)) { + statement.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); + } + + results = session.execute(statement); + + } catch (Exception ex) { + logger.error(EELFLoggerDelegate.errorLogger, "Execute Get Error" + ex.getMessage(),AppMessages.UNKNOWNERROR+ "[" + queryObject + .getQuery() + "]", ErrorSeverity.ERROR, ErrorTypes.QUERYERROR, ex); + throw new MusicServiceException("Execute Get Error" + ex.getMessage()); + } + + return results; + + } + + /** + * This method performs DDL operations on Cassandra using consistency level ONE. + * + * @param queryObject Object containing cassandra prepared query and values. + */ + public ResultSet executeOneConsistencyGet(PreparedQueryObject queryObject) + throws MusicServiceException, MusicQueryException { + return executeGet(queryObject, CONSISTENCY_LEVEL_ONE); + } + + /** + * + * This method performs DDL operation on Cassandra using consistency level LOCAL_QUORUM. + * + * @param queryObject Object containing cassandra prepared query and values. + */ + public ResultSet executeLocalQuorumConsistencyGet(PreparedQueryObject queryObject) + throws MusicServiceException, MusicQueryException { + return executeGet(queryObject, CONSISTENCY_LEVEL_LOCAL_QUORUM); + } + + /** + * + * This method performs DDL operation on Cassandra using consistency level QUORUM. + * + * @param queryObject Object containing cassandra prepared query and values. + */ + public ResultSet executeQuorumConsistencyGet(PreparedQueryObject queryObject) + throws MusicServiceException, MusicQueryException { + return executeGet(queryObject, CONSISTENCY_LEVEL_QUORUM); + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/MusicDataStoreHandle.java b/music-core/src/main/java/org/onap/music/datastore/MusicDataStoreHandle.java new file mode 100644 index 00000000..09fe0d35 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/MusicDataStoreHandle.java @@ -0,0 +1,127 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * Modifications Copyright (C) 2019 IBM. + * =================================================================== + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * 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.datastore; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicUtil; + +import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.TableMetadata; + +public class MusicDataStoreHandle { + + private static MusicDataStore mDstoreHandle = null; + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicDataStoreHandle.class); + + private MusicDataStoreHandle(){ + throw new IllegalStateException("Utility class"); + } + + /** + * + * @param remoteIp + * @return + */ + public static MusicDataStore getDSHandle(String remoteIp) { + logger.info(EELFLoggerDelegate.metricsLogger,"Acquiring data store handle"); + long start = System.currentTimeMillis(); + if (mDstoreHandle == null) { + mDstoreHandle = new MusicDataStore(remoteIp); + } + long end = System.currentTimeMillis(); + logger.info(EELFLoggerDelegate.metricsLogger,"Time taken to acquire data store handle:" + (end - start) + " ms"); + return mDstoreHandle; + } + + /** + * + * @return + * @throws MusicServiceException + */ + public static MusicDataStore getDSHandle() throws MusicServiceException { + logger.info(EELFLoggerDelegate.metricsLogger,"Acquiring data store handle"); + long start = System.currentTimeMillis(); + if (mDstoreHandle == null) { + // Quick Fix - Best to put this into every call to getDSHandle? + if (!"localhost".equals(MusicUtil.getMyCassaHost())) { + mDstoreHandle = new MusicDataStore(MusicUtil.getMyCassaHost()); + } else { + mDstoreHandle = new MusicDataStore(); + } + } + if(mDstoreHandle.getSession() == null) { + String message = "Connection to Cassandra has not been enstablished." + + " Please check connection properites and reboot."; + logger.info(EELFLoggerDelegate.applicationLogger, message); + throw new MusicServiceException(message); + } + long end = System.currentTimeMillis(); + logger.info(EELFLoggerDelegate.metricsLogger,"Time taken to acquire data store handle:" + (end - start) + " ms"); + return mDstoreHandle; + } + + public static void setMDstoreHandle(MusicDataStore dsHandle) { + mDstoreHandle = dsHandle; + } + + /** + * + * @param keyspace + * @param tablename + * @return + * @throws MusicServiceException + */ + public static TableMetadata returnColumnMetadata(String keyspace, String tablename) throws MusicServiceException { + return getDSHandle().returnColumnMetadata(keyspace, tablename); + } + + /** + * + * @param keyspace + * @param tablename + * @return + * @throws MusicServiceException + */ + public static KeyspaceMetadata returnkeyspaceMetadata(String keyspace) throws MusicServiceException { + return getDSHandle().returnKeyspaceMetadata(keyspace); + } + + /** + * + * @param results + * @return + * @throws MusicServiceException + */ + public static Map<String, HashMap<String, Object>> marshallResults(ResultSet results) throws MusicServiceException { + return getDSHandle().marshalData(results); + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/PreparedQueryObject.java b/music-core/src/main/java/org/onap/music/datastore/PreparedQueryObject.java new file mode 100644 index 00000000..fdac50be --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/PreparedQueryObject.java @@ -0,0 +1,176 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017-2019 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.datastore; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author srupane + * + */ +public class PreparedQueryObject { + + + private List<Object> values; + private StringBuilder query; + private String consistency; + private String keyspaceName; + private String tableName; + private String operation; + private String primaryKeyValue; + + + /** + * Create PreparedQueryObject + */ + public PreparedQueryObject() { + this.values = new ArrayList<>(); + this.query = new StringBuilder(); + } + + /** + * Create PreparedQueryObject + * @param query query portion of the prepared query + */ + public PreparedQueryObject(String query) { + this.values = new ArrayList<>(); + this.query = new StringBuilder(query); + } + + /** + * Create PreparedQueryObject + * @param query query portion of the prepared query + * @param values to be added to the query string as prepared query + */ + public PreparedQueryObject(String query, Object...values) { + this.query = new StringBuilder(query); + this.values = new ArrayList<>(); + for (Object value: values) { + this.values.add(value); + } + } + + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getOperation() { + if (operation!=null) return operation; + if (query.length()==0) return null; + String queryStr = query.toString().toLowerCase(); + String firstOp = null; + int firstOpChar = query.length(); + if (queryStr.indexOf("insert")>-1 && queryStr.indexOf("insert")<firstOpChar) { + firstOp = "insert"; + firstOpChar = queryStr.indexOf("insert"); + } + if (queryStr.indexOf("update")>-1 && queryStr.indexOf("update")<firstOpChar) { + firstOp = "update"; + firstOpChar = queryStr.indexOf("update"); + } + if (queryStr.indexOf("delete")>-1 && queryStr.indexOf("delete")<firstOpChar) { + firstOp = "delete"; + firstOpChar = queryStr.indexOf("delete"); + } + if (queryStr.indexOf("select")>-1 && queryStr.indexOf("select")<firstOpChar) { + firstOp = "select"; + firstOpChar = queryStr.indexOf("select"); + } + return firstOp; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getPrimaryKeyValue() { + return primaryKeyValue; + } + + public void setPrimaryKeyValue(String primaryKeyValue) { + this.primaryKeyValue = primaryKeyValue; + } + + public String getConsistency() { + return consistency; + } + + public void setConsistency(String consistency) { + this.consistency = consistency; + } + + /** + * @return values to be set as part of the prepared query + */ + public List<Object> getValues() { + return values; + } + + /** + * @param o object to be added as a value to the prepared query, in order + */ + public void addValue(Object o) { + this.values.add(o); + } + + /** + * Add values to the preparedQuery + * @param objs ordered list of objects to be added as values to the prepared query + */ + public void addValues(Object... objs) { + for (Object obj: objs) { + this.values.add(obj); + } + } + + /** + * @param s + */ + public void appendQueryString(String s) { + this.query.append(s); + } + public void replaceQueryString(String s) { + this.query.replace(0, query.length(), s); + } + + /** + * @return the query + */ + public String getQuery() { + return this.query.toString(); + } +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JSONObject.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JSONObject.java new file mode 100644 index 00000000..a1524cc6 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JSONObject.java @@ -0,0 +1,37 @@ +package org.onap.music.datastore.jsonobjects; +/* + * ============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============================================= + * ==================================================================== + */ + + +public class JSONObject { + + private String data; + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java new file mode 100644 index 00000000..988ba3a8 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java @@ -0,0 +1,313 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.Condition; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicUtil; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.TableMetadata; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "JsonTable", description = "Json model for delete") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonDelete { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonDelete.class); + + private List<String> columns = null; + private Map<String, String> consistencyInfo; + private Map<String, Object> conditions; + private String ttl; + private String timestamp; + private String keyspaceName; + private String tableName; + private StringBuilder rowIdString; + private String primarKeyValue; + + + @ApiModelProperty(value = "Conditions") + public Map<String, Object> getConditions() { + return conditions; + } + + public void setConditions(Map<String, Object> conditions) { + this.conditions = conditions; + } + + @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic") + public Map<String, String> getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map<String, String> consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + @ApiModelProperty(value = "Column values") + public List<String> getColumns() { + return columns; + } + + public void setColumns(List<String> columns) { + this.columns = columns; + } + + + @ApiModelProperty(value = "Time to live information") + public String getTtl() { + return ttl; + } + + public void setTtl(String ttl) { + this.ttl = ttl; + } + + @ApiModelProperty(value = "Time stamp") + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public StringBuilder getRowIdString() { + return rowIdString; + } + + public void setRowIdString(StringBuilder rowIdString) { + this.rowIdString = rowIdString; + } + + public String getPrimarKeyValue() { + return primarKeyValue; + } + + public void setPrimarKeyValue(String primarKeyValue) { + this.primarKeyValue = primarKeyValue; + } + + + public PreparedQueryObject genDeletePreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException { + if (logger.isDebugEnabled()) { + logger.debug("Coming inside genUpdatePreparedQueryObj method " + this.getKeyspaceName()); + logger.debug("Coming inside genUpdatePreparedQueryObj method " + this.getTableName()); + } + + PreparedQueryObject queryObject = new PreparedQueryObject(); + + if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty()) + || (this.getTableName() == null || this.getTableName().isEmpty())){ + + + throw new MusicQueryException("one or more path parameters are not set, please check and try again", + Status.BAD_REQUEST.getStatusCode()); + } + + EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) "); + + if(this == null) { + logger.error(EELFLoggerDelegate.errorLogger,"Required HTTP Request body is missing.", AppMessages.MISSINGDATA ,ErrorSeverity.WARN, ErrorTypes.DATAERROR); + + throw new MusicQueryException("Required HTTP Request body is missing.", + Status.BAD_REQUEST.getStatusCode()); + } + StringBuilder columnString = new StringBuilder(); + + int counter = 0; + List<String> columnList = this.getColumns(); + if (columnList != null) { + for (String column : columnList) { + columnString.append(column); + if (counter != columnList.size() - 1) + columnString.append(","); + counter = counter + 1; + } + } + + // get the row specifier + RowIdentifier rowId = null; + try { + rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject); + this.setRowIdString(rowId.rowIdString); + this.setPrimarKeyValue(rowId.primarKeyValue); + if(rowId == null || rowId.primarKeyValue.isEmpty()) { + + throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.", + Status.BAD_REQUEST.getStatusCode()); + } + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes + .GENERALSERVICEERROR, ex); + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();*/ + throw new MusicQueryException(AppMessages.UNKNOWNERROR.toString(), Status.BAD_REQUEST.getStatusCode()); + } + String rowSpec = rowId.rowIdString.toString(); + + if ((columnList != null) && (!rowSpec.isEmpty())) { + queryObject.appendQueryString("DELETE " + columnString + " FROM " + this.getKeyspaceName() + "." + + this.getTableName() + " WHERE " + rowSpec + ";"); + } + + if ((columnList == null) && (!rowSpec.isEmpty())) { + queryObject.appendQueryString("DELETE FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + + rowSpec + ";"); + } + + if ((columnList != null) && (rowSpec.isEmpty())) { + queryObject.appendQueryString( + "DELETE " + columnString + " FROM " + this.getKeyspaceName() + "." + rowSpec + ";"); + } + // get the conditional, if any + Condition conditionInfo; + if (this.getConditions() == null) { + conditionInfo = null; + } else { + // to avoid parsing repeatedly, just send the select query to + // obtain row + PreparedQueryObject selectQuery = new PreparedQueryObject(); + selectQuery.appendQueryString("SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + + rowId.rowIdString + ";"); + selectQuery.addValue(rowId.primarKeyValue); + conditionInfo = new Condition(this.getConditions(), selectQuery); + } + + String consistency = this.getConsistencyInfo().get("type"); + + + if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency")!=null) { + if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) { + queryObject.setConsistency(this.getConsistencyInfo().get("consistency")); + } else { + throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode()); + } + } + + queryObject.setOperation("delete"); + + return queryObject; + } + + + /** + * + * @param keyspace + * @param tablename + * @param rowParams + * @param queryObject + * @return + * @throws MusicServiceException + */ + private RowIdentifier getRowIdentifier(String keyspace, String tablename, + MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject) + throws MusicServiceException { + StringBuilder rowSpec = new StringBuilder(); + int counter = 0; + TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename); + if (tableInfo == null) { + logger.error(EELFLoggerDelegate.errorLogger, + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + throw new MusicServiceException( + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + } + StringBuilder primaryKey = new StringBuilder(); + for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) { + String keyName = entry.getKey(); + List<String> valueList = entry.getValue(); + String indValue = valueList.get(0); + DataType colType = null; + Object formattedValue = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + formattedValue = MusicUtil.convertToActualDataType(colType, indValue); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) { + primaryKey.append(indValue); + } + rowSpec.append(keyName + "= ?"); + queryObject.addValue(formattedValue); + if (counter != rowParams.size() - 1) { + rowSpec.append(" AND "); + } + counter = counter + 1; + } + return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject); + } + + private class RowIdentifier { + private String primarKeyValue; + private StringBuilder rowIdString; + @SuppressWarnings("unused") + public PreparedQueryObject queryObject; // the string with all the row + // identifiers separated by AND + + public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString, + PreparedQueryObject queryObject) { + this.primarKeyValue = primaryKeyValue; + this.rowIdString = rowIdString; + this.queryObject = queryObject; + } + } +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonIndex.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonIndex.java new file mode 100644 index 00000000..a06e8ea9 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonIndex.java @@ -0,0 +1,120 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +@ApiModel(value = "JsonIndex", description = "Index Object") +public class JsonIndex { + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonIndex.class); + + private String indexName; + private String keyspaceName; + private String tableName; + private String fieldName; + + public JsonIndex(String indexName,String keyspaceName,String tableName,String fieldName) { + this.indexName = indexName; + this.keyspaceName= keyspaceName; + this.tableName = tableName; + this.fieldName = fieldName; + } + + @ApiModelProperty(value = "Index Name") + public String getIndexName() { + return indexName; + } + + public JsonIndex setIndexName(String indexName) { + this.indexName = indexName; + return this; + } + + @ApiModelProperty(value = "Keyspace name") + public String getKeyspaceName() { + return keyspaceName; + } + + public JsonIndex setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + return this; + } + + public JsonIndex setTableName(String tableName) { + this.tableName = tableName; + return this; + } + + @ApiModelProperty(value = "Table name") + public String getTableName() { + return tableName; + } + + public JsonIndex setFieldName(String fieldName) { + this.fieldName = fieldName; + return this; + } + + @ApiModelProperty(value = "Field name") + public String getFieldName() { + return fieldName; + } + + public PreparedQueryObject genCreateIndexQuery() { + + if (logger.isDebugEnabled()) { + logger.debug("Came inside genCreateIndexQuery method"); + } + + logger.info("genCreateIndexQuery indexName ::" + indexName); + logger.info("genCreateIndexQuery keyspaceName ::" + keyspaceName); + logger.info("genCreateIndexQuery tableName ::" + tableName); + logger.info("genCreateIndexQuery fieldName ::" + fieldName); + + long start = System.currentTimeMillis(); + + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString("Create index if not exists " + this.getIndexName() + " on " + this.getKeyspaceName() + "." + + this.getTableName() + " (" + this.getFieldName() + ");"); + + long end = System.currentTimeMillis(); + + logger.info(EELFLoggerDelegate.applicationLogger, + "Time taken for setting up query in create index:" + (end - start)); + + logger.info(EELFLoggerDelegate.applicationLogger, + " create index query :" + query.getQuery()); + + return query; + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java new file mode 100644 index 00000000..2f685cfe --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java @@ -0,0 +1,415 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicUtil; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.TableMetadata; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "InsertTable", description = "Json model for table vlaues insert") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonInsert implements Serializable { + private static final long serialVersionUID = 1L; + private String keyspaceName; + private String tableName; + private transient Map<String, Object> values; + private String ttl; + private String timestamp; + private transient Map<String, Object> rowSpecification; + private Map<String, String> consistencyInfo; + private Map<String, byte[]> objectMap; + private String primaryKeyVal; + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonInsert.class); + + @ApiModelProperty(value = "objectMap",hidden = true) + public Map<String, byte[]> getObjectMap() { + return objectMap; + } + + public void setObjectMap(Map<String, byte[]> objectMap) { + this.objectMap = objectMap; + } + + @ApiModelProperty(value = "keyspace") + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @ApiModelProperty(value = "Table name") + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic") + public Map<String, String> getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map<String, String> consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + @ApiModelProperty(value = "Columns and tables support an optional " + + "expiration period called TTL (time-to-live) in seconds.", + notes="TTL precision is one second, which is calculated by the coordinator " + + "node. When using TTL, ensure that all nodes in the cluster have synchronized clocks.",allowEmptyValue = true) + public String getTtl() { + return ttl; + } + + public void setTtl(String ttl) { + this.ttl = ttl; + } + + @ApiModelProperty(value = "Time stamp (epoch_in_microseconds)", + notes = "Marks inserted data (write time) with TIMESTAMP. " + + "Enter the time since epoch (January 1, 1970) in microseconds." + + "By default, the actual time of write is used.", allowEmptyValue = true) + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + @ApiModelProperty(value = "Json Object of key/values", notes="Where key is the column name and value is the data value for that column.", + example = "{'emp_id': 'df98a3d40cd6','emp_name': 'john'," + + "'emp_salary': 50,'address':{'street' : '1 Some way','city' : 'New York'}}") + public Map<String, Object> getValues() { + return values; + } + + public void setValues(Map<String, Object> values) { + this.values = values; + } + + @ApiModelProperty(value = "Information for selecting specific rows for insert",hidden = true) + public Map<String, Object> getRowSpecification() { + return rowSpecification; + } + + public void setRowSpecification(Map<String, Object> rowSpecification) { + this.rowSpecification = rowSpecification; + } + + public String getPrimaryKeyVal() { + return primaryKeyVal; + } + + public void setPrimaryKeyVal(String primaryKeyVal) { + this.primaryKeyVal = primaryKeyVal; + } + + public byte[] serialize() { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutput out = null; + try { + out = new ObjectOutputStream(bos); + out.writeObject(this); + } catch (IOException e) { + logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.IOERROR, ErrorSeverity.ERROR, ErrorTypes.DATAERROR); + } + return bos.toByteArray(); + } + + /** + * Generate TableInsertQuery + * @return + * @throws MusicQueryException + */ + public PreparedQueryObject genInsertPreparedQueryObj() throws MusicQueryException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + TableMetadata tableInfo = null; + try { + tableInfo = MusicDataStoreHandle.returnColumnMetadata(this.getKeyspaceName(), this.getTableName()); + if(tableInfo == null) { + throw new MusicQueryException("Table name doesn't exists. Please check the table name.", + Status.BAD_REQUEST.getStatusCode()); + } + } catch (MusicServiceException e) { + logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + throw new MusicQueryException(e.getMessage(),Status.BAD_REQUEST.getStatusCode()); + + } + String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName(); + StringBuilder fieldsString = new StringBuilder("(vector_ts,"); + String vectorTs = + String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + StringBuilder valueString = new StringBuilder("(" + "?" + ","); + queryObject.addValue(vectorTs); + + Map<String, Object> valuesMap = this.getValues(); + if (valuesMap==null) { + throw new MusicQueryException("Nothing to insert. No values provided in request.", + Status.BAD_REQUEST.getStatusCode()); + } + int counter = 0; + String primaryKey = ""; + for (Map.Entry<String, Object> entry : valuesMap.entrySet()) { + fieldsString.append("" + entry.getKey()); + Object valueObj = entry.getValue(); + if (primaryKeyName.equals(entry.getKey())) { + primaryKey = entry.getValue() + ""; + primaryKey = primaryKey.replace("'", "''"); + } + DataType colType = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + } catch(NullPointerException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey + (), AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex); + throw new MusicQueryException("Invalid column name : " + entry.getKey(), + Status.BAD_REQUEST.getStatusCode()); + } + + Object formattedValue = null; + try { + formattedValue = MusicUtil.convertToActualDataType(colType, valueObj); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + valueString.append("?"); + + queryObject.addValue(formattedValue); + + if (counter == valuesMap.size() - 1) { + fieldsString.append(")"); + valueString.append(")"); + } else { + fieldsString.append(","); + valueString.append(","); + } + counter = counter + 1; + } + + //blobs.. + Map<String, byte[]> objectMap = this.getObjectMap(); + if(objectMap != null) { + for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) { + if(counter > 0) { + fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ","); + valueString.replace(valueString.length()-1, valueString.length(), ","); + } + fieldsString.append("" + entry.getKey()); + byte[] valueObj = entry.getValue(); + if (primaryKeyName.equals(entry.getKey())) { + primaryKey = entry.getValue() + ""; + primaryKey = primaryKey.replace("'", "''"); + } + DataType colType = tableInfo.getColumn(entry.getKey()).getType(); + ByteBuffer formattedValue = null; + if(colType.toString().toLowerCase().contains("blob")) { + formattedValue = MusicUtil.convertToActualDataType(colType, valueObj); + } + valueString.append("?"); + queryObject.addValue(formattedValue); + counter = counter + 1; + fieldsString.append(","); + valueString.append(","); + } + } + this.setPrimaryKeyVal(primaryKey); + if(primaryKey == null || primaryKey.length() <= 0) { + logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName ); + throw new MusicQueryException("Some required partition key parts are missing: " + primaryKeyName, + Status.BAD_REQUEST.getStatusCode()); + } + + fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")"); + valueString.replace(valueString.length()-1, valueString.length(), ")"); + + queryObject.appendQueryString("INSERT INTO " + this.getKeyspaceName() + "." + this.getTableName() + " " + + fieldsString + " VALUES " + valueString); + + String ttl = this.getTtl(); + String timestamp = this.getTimestamp(); + + if ((ttl != null) && (timestamp != null)) { + logger.info(EELFLoggerDelegate.applicationLogger, "both there"); + queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?"); + queryObject.addValue(Integer.parseInt(ttl)); + queryObject.addValue(Long.parseLong(timestamp)); + } + + if ((ttl != null) && (timestamp == null)) { + logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there"); + queryObject.appendQueryString(" USING TTL ?"); + queryObject.addValue(Integer.parseInt(ttl)); + } + + if ((ttl == null) && (timestamp != null)) { + logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there"); + queryObject.appendQueryString(" USING TIMESTAMP ?"); + queryObject.addValue(Long.parseLong(timestamp)); + } + + queryObject.appendQueryString(";"); + + String consistency = this.getConsistencyInfo().get("type"); + if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) { + if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) { + queryObject.setConsistency(this.getConsistencyInfo().get("consistency")); + } else { + throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode()); + } + } + queryObject.setOperation("insert"); + + logger.info("Data insert Query ::::: " + queryObject.getQuery()); + + return queryObject; + } + + /** + * + * @param rowParams + * @return + * @throws MusicQueryException + */ + public PreparedQueryObject genSelectCriticalPreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException { + + PreparedQueryObject queryObject = new PreparedQueryObject(); + + if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty()) + || (this.getTableName() == null || this.getTableName().isEmpty())){ + throw new MusicQueryException("one or more path parameters are not set, please check and try again", + Status.BAD_REQUEST.getStatusCode()); + } + EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) "); + RowIdentifier rowId = null; + try { + rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject); + this.setPrimaryKeyVal(rowId.primarKeyValue); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes + .GENERALSERVICEERROR, ex); + throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode()); + } + + queryObject.appendQueryString( + "SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + rowId.rowIdString + ";"); + + return queryObject; + } + + private class RowIdentifier { + public String primarKeyValue; + public StringBuilder rowIdString; + @SuppressWarnings("unused") + public PreparedQueryObject queryObject; // the string with all the row + // identifiers separated by AND + + public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString, + PreparedQueryObject queryObject) { + this.primarKeyValue = primaryKeyValue; + this.rowIdString = rowIdString; + this.queryObject = queryObject; + } + } + + /** + * + * @param keyspace + * @param tablename + * @param rowParams + * @param queryObject + * @return + * @throws MusicServiceException + */ + private RowIdentifier getRowIdentifier(String keyspace, String tablename, + MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject) + throws MusicServiceException { + StringBuilder rowSpec = new StringBuilder(); + int counter = 0; + TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename); + if (tableInfo == null) { + logger.error(EELFLoggerDelegate.errorLogger, + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + throw new MusicServiceException( + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + } + StringBuilder primaryKey = new StringBuilder(); + for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) { + String keyName = entry.getKey(); + List<String> valueList = entry.getValue(); + String indValue = valueList.get(0); + DataType colType = null; + Object formattedValue = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + formattedValue = MusicUtil.convertToActualDataType(colType, indValue); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) { + primaryKey.append(indValue); + } + rowSpec.append(keyName + "= ?"); + queryObject.addValue(formattedValue); + if (counter != rowParams.size() - 1) { + rowSpec.append(" AND "); + } + counter = counter + 1; + } + return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject); + } + + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java new file mode 100644 index 00000000..cada1c00 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java @@ -0,0 +1,163 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import java.util.Map; + +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.main.MusicUtil; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "JsonTable", description = "Json model creating new keyspace") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonKeySpace { + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonKeySpace.class); + private String keyspaceName; + private Map<String, Object> replicationInfo; + private String durabilityOfWrites; + private Map<String, String> consistencyInfo; + + @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic") + public Map<String, String> getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map<String, String> consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + @ApiModelProperty(value = "Replication information") + public Map<String, Object> getReplicationInfo() { + return replicationInfo; + } + + public void setReplicationInfo(Map<String, Object> replicationInfo) { + this.replicationInfo = replicationInfo; + } + + @ApiModelProperty(value = "Durability", allowableValues = "true,false") + public String getDurabilityOfWrites() { + return durabilityOfWrites; + } + + public void setDurabilityOfWrites(String durabilityOfWrites) { + this.durabilityOfWrites = durabilityOfWrites; + } + + @ApiModelProperty(value = "Keyspace name") + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + /** + * Will generate query to create Keyspacce. + * + * @throws MusicQueryException + */ + @SuppressWarnings("deprecation") + public PreparedQueryObject genCreateKeyspaceQuery() throws MusicQueryException { + + if (logger.isDebugEnabled()) { + logger.debug("Came inside createKeyspace method"); + } + + String keyspaceName = this.getKeyspaceName(); + String durabilityOfWrites = this.getDurabilityOfWrites(); + String consistency = MusicUtil.EVENTUAL; + + logger.info("genCreateKeyspaceQuery keyspaceName ::" + keyspaceName); + logger.info("genCreateKeyspaceQuery class :: " + this.getReplicationInfo().get("class")); + logger.info("genCreateKeyspaceQuery replication_factor :: " + this.getReplicationInfo().get("replication_factor")); + logger.info("genCreateKeyspaceQuery durabilityOfWrites :: " + durabilityOfWrites); + + PreparedQueryObject queryObject = new PreparedQueryObject(); + + if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) { + if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) { + queryObject.setConsistency(this.getConsistencyInfo().get("consistency")); + }else { + throw new MusicQueryException("Invalid Consistency type",Status.BAD_REQUEST.getStatusCode()); + } + } + + long start = System.currentTimeMillis(); + Map<String, Object> replicationInfo = this.getReplicationInfo(); + String repString = null; + try { + repString = "{" + MusicUtil.jsonMaptoSqlString(replicationInfo, ",") + "}"; + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + } + queryObject.appendQueryString("CREATE KEYSPACE " + keyspaceName + " WITH replication = " + repString); + if (this.getDurabilityOfWrites() != null) { + queryObject.appendQueryString(" AND durable_writes = " + this.getDurabilityOfWrites()); + } + queryObject.appendQueryString(";"); + long end = System.currentTimeMillis(); + logger.info(EELFLoggerDelegate.applicationLogger, + "Time taken for setting up query in create keyspace:" + (end - start)); + + return queryObject; + } + + /** + * Will generate Query to drop a keyspace. + * + * @return + */ + public PreparedQueryObject genDropKeyspaceQuery() { + if (logger.isDebugEnabled()) { + logger.debug("Coming inside genDropKeyspaceQuery method "+this.getKeyspaceName()); + } + + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString("DROP KEYSPACE " + this.getKeyspaceName() + ";"); + + return queryObject; + } + + @Override + public String toString() { + return "CassaKeyspaceObject [keyspaceName=" + keyspaceName + ", replicationInfo=" + replicationInfo + + "durabilityOfWrites=" + durabilityOfWrites + "]"; + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java new file mode 100644 index 00000000..86bbe3dc --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java @@ -0,0 +1,44 @@ +/* + * ============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.datastore.jsonobjects; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "Json Leasesd Lock", description = "model for leased lock") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonLeasedLock { + private long leasePeriod; + + @ApiModelProperty(value = "Lease period") + public long getLeasePeriod() { + return leasePeriod; + } + + public void setLeasePeriod(long leasePeriod) { + this.leasePeriod = leasePeriod; + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonLock.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonLock.java new file mode 100644 index 00000000..f353c018 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonLock.java @@ -0,0 +1,49 @@ +/* + * ============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.datastore.jsonobjects; + +import org.onap.music.lockingservice.cassandra.LockType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "Json Lock Type", description = "Model for Lock Type") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonLock { + private LockType locktype; + + @ApiModelProperty( + value = "Type of music lock", + name = "lockType", + allowEmptyValue = false, + allowableValues = "READ|WRITE") + public LockType getLocktype() { + return this.locktype; + } + + public void setLockType(LockType locktype) { + this.locktype = locktype; + } +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java new file mode 100644 index 00000000..e354b4b0 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java @@ -0,0 +1,208 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicUtil; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.TableMetadata; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonSelect implements Serializable { + private Map<String, String> consistencyInfo; + private String keyspaceName; + private String tableName; + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonSelect.class); + + + + public Map<String, String> getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map<String, String> consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public byte[] serialize() { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutput out = null; + try { + out = new ObjectOutputStream(bos); + out.writeObject(this); + } catch (IOException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getMessage(), e); + } + return bos.toByteArray(); + } + + /** + * genSelectQuery + * + * @return + * @throws MusicQueryException + */ + public PreparedQueryObject genSelectQuery(MultivaluedMap<String, String> rowParams) throws MusicQueryException { + + if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty()) + || (this.getTableName() == null || this.getTableName().isEmpty())){ + throw new MusicQueryException("one or more path parameters are not set, please check and try again", + Status.BAD_REQUEST.getStatusCode()); + } + EELFLoggerDelegate.mdcPut("keyspace", "( " + this.getKeyspaceName() + " ) "); + PreparedQueryObject queryObject = new PreparedQueryObject(); + + if (rowParams.isEmpty()) { // select all + queryObject.appendQueryString("SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + ";"); + } else { + int limit = -1; // do not limit the number of results + try { + queryObject = selectSpecificQuery(this.getKeyspaceName(), this.getTableName(), rowParams, limit); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, + ErrorTypes.GENERALSERVICEERROR, ex); + + throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode()); + } + } + + return queryObject; + } + + public PreparedQueryObject selectSpecificQuery(String keyspace, + String tablename, MultivaluedMap<String, String> rowParams, int limit) + throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + StringBuilder rowIdString = getRowIdentifier(keyspace, + tablename,rowParams,queryObject).rowIdString; + queryObject.appendQueryString( + "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowIdString); + if (limit != -1) { + queryObject.appendQueryString(" LIMIT " + limit); + } + queryObject.appendQueryString(";"); + return queryObject; + } + + private class RowIdentifier { + public String primarKeyValue; + public StringBuilder rowIdString; + @SuppressWarnings("unused") + public PreparedQueryObject queryObject; // the string with all the row + // identifiers separated by AND + + public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString, + PreparedQueryObject queryObject) { + this.primarKeyValue = primaryKeyValue; + this.rowIdString = rowIdString; + this.queryObject = queryObject; + } + } + + /** + * + * @param keyspace + * @param tablename + * @param rowParams + * @param queryObject + * @return + * @throws MusicServiceException + */ + private RowIdentifier getRowIdentifier(String keyspace, String tablename, + MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject) + throws MusicServiceException { + StringBuilder rowSpec = new StringBuilder(); + int counter = 0; + TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename); + if (tableInfo == null) { + logger.error(EELFLoggerDelegate.errorLogger, + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + throw new MusicServiceException( + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + } + StringBuilder primaryKey = new StringBuilder(); + for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) { + String keyName = entry.getKey(); + List<String> valueList = entry.getValue(); + String indValue = valueList.get(0); + DataType colType = null; + Object formattedValue = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + formattedValue = MusicUtil.convertToActualDataType(colType, indValue); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) { + primaryKey.append(indValue); + } + rowSpec.append(keyName + "= ?"); + queryObject.addValue(formattedValue); + if (counter != rowParams.size() - 1) { + rowSpec.append(" AND "); + } + counter = counter + 1; + } + return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject); + } + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java new file mode 100644 index 00000000..0ba1a7ef --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java @@ -0,0 +1,363 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import java.util.Map; + +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.main.MusicUtil; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "JsonTable", description = "Defines the Json for Creating a new Table.") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonTable { + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonTable.class); + + private String keyspaceName; + private String tableName; + + private Map<String, String> fields; + private Map<String, Object> properties; + private String primaryKey; + private String partitionKey; + private String clusteringKey; + private String filteringKey; + private String clusteringOrder; + private Map<String, String> consistencyInfo; + + @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic") + public Map<String, String> getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map<String, String> consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + @ApiModelProperty(value = "Properties") + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + + @ApiModelProperty(value = "Fields") + public Map<String, String> getFields() { + return fields; + } + + public void setFields(Map<String, String> fields) { + this.fields = fields; + } + + @ApiModelProperty(value = "KeySpace Name") + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @ApiModelProperty(value = "Table Name") + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + @ApiModelProperty(value = "Clustering Order", notes = "") + public String getClusteringOrder() { + return clusteringOrder; + } + + public void setClusteringOrder(String clusteringOrder) { + this.clusteringOrder = clusteringOrder; + } + + @ApiModelProperty(value = "Primary Key") + public String getPrimaryKey() { + return primaryKey; + } + + public void setPrimaryKey(String primaryKey) { + this.primaryKey = primaryKey; + } + + public String getClusteringKey() { + return clusteringKey; + } + + public void setClusteringKey(String clusteringKey) { + this.clusteringKey = clusteringKey; + } + + public String getFilteringKey() { + return filteringKey; + } + + public void setFilteringKey(String filteringKey) { + this.filteringKey = filteringKey; + } + + public String getPartitionKey() { + return partitionKey; + } + + public void setPartitionKey(String partitionKey) { + this.partitionKey = partitionKey; + } + + public PreparedQueryObject genCreateTableQuery() throws MusicQueryException { + String primaryKey = null; + String partitionKey = this.getPartitionKey(); + String clusterKey = this.getClusteringKey(); + String filteringKey = this.getFilteringKey(); + if (filteringKey != null) { + clusterKey = clusterKey + "," + filteringKey; + } + primaryKey = this.getPrimaryKey(); // get primaryKey if available + + PreparedQueryObject queryObject = new PreparedQueryObject(); + // first read the information about the table fields + Map<String, String> fields = this.getFields(); + if (fields == null) { + throw new MusicQueryException( + "Create Table Error: No fields in request", Status.BAD_REQUEST.getStatusCode()); + } + StringBuilder fieldsString = new StringBuilder("(vector_ts text,"); + int counter = 0; + for (Map.Entry<String, String> entry : fields.entrySet()) { + if (entry.getKey().equals("PRIMARY KEY")) { + primaryKey = entry.getValue(); // replaces primaryKey + primaryKey = primaryKey.trim(); + } + else { + if (counter == 0 ) + fieldsString.append("" + entry.getKey() + " " + entry.getValue() + ""); + else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + ""); + } + + if (counter != (fields.size() - 1) ) { + counter = counter + 1; + } else { + + if((primaryKey != null) && (partitionKey == null)) { + primaryKey = primaryKey.trim(); + int count1 = StringUtils.countMatches(primaryKey, ')'); + int count2 = StringUtils.countMatches(primaryKey, '('); + if (count1 != count2) { + throw new MusicQueryException( + "Create Table Error: primary key '(' and ')' do not match, primary key=" + primaryKey, + Status.BAD_REQUEST.getStatusCode()); + } + + if ( primaryKey.indexOf('(') == -1 || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) == primaryKey.length() ) ) { + if (primaryKey.contains(",") ) { + partitionKey= primaryKey.substring(0,primaryKey.indexOf(',')); + partitionKey=partitionKey.replaceAll("[\\(]+",""); + clusterKey=primaryKey.substring(primaryKey.indexOf(',')+1); // make sure index + clusterKey=clusterKey.replaceAll("[)]+", ""); + } else { + partitionKey=primaryKey; + partitionKey=partitionKey.replaceAll("[\\)]+",""); + partitionKey=partitionKey.replaceAll("[\\(]+",""); + clusterKey=""; + } + } else { // not null and has ) before the last char + partitionKey= primaryKey.substring(0,primaryKey.indexOf(')')); + partitionKey=partitionKey.replaceAll("[\\(]+",""); + partitionKey = partitionKey.trim(); + clusterKey= primaryKey.substring(primaryKey.indexOf(')')); + clusterKey=clusterKey.replaceAll("[\\(]+",""); + clusterKey=clusterKey.replaceAll("[\\)]+",""); + clusterKey = clusterKey.trim(); + if (clusterKey.indexOf(',') == 0) { + clusterKey=clusterKey.substring(1); + } + clusterKey = clusterKey.trim(); + if (clusterKey.equals(",") ) + clusterKey=""; // print error if needed ( ... ),) + } + + if (!(partitionKey.isEmpty() || clusterKey.isEmpty()) + && (partitionKey.equalsIgnoreCase(clusterKey) || + clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) { + logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey + " and primary key=" + primaryKey ); + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError( + "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ") of" + + " primary key=" + primaryKey) + .toMap()).build();*/ + throw new MusicQueryException("Create Table primary key error: clusterKey(" + clusterKey + + ") equals/contains/overlaps partitionKey(" + partitionKey + ") of" + " primary key=" + + primaryKey, Status.BAD_REQUEST.getStatusCode()); + + } + + if (partitionKey.isEmpty() ) + primaryKey=""; + else if (clusterKey.isEmpty() ) + primaryKey=" (" + partitionKey + ")"; + else + primaryKey=" (" + partitionKey + ")," + clusterKey; + + + if (primaryKey != null) + fieldsString.append(", PRIMARY KEY (" + primaryKey + " )"); + + } else { // end of length > 0 + + if (!(partitionKey.isEmpty() || clusterKey.isEmpty()) + && (partitionKey.equalsIgnoreCase(clusterKey) || + clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) { + logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey); + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError( + "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")") + .toMap()).build();*/ + throw new MusicQueryException( + "Create Table primary key error: clusterKey(" + clusterKey + + ") equals/contains/overlaps partitionKey(" + partitionKey + ")", + Status.BAD_REQUEST.getStatusCode()); + } + + if (partitionKey.isEmpty() ) + primaryKey=""; + else if (clusterKey.isEmpty() ) + primaryKey=" (" + partitionKey + ")"; + else + primaryKey=" (" + partitionKey + ")," + clusterKey; + + if (primaryKey != null) + fieldsString.append(", PRIMARY KEY (" + primaryKey + " )"); + } + fieldsString.append(")"); + + } // end of last field check + + } // end of for each + // information about the name-value style properties + Map<String, Object> propertiesMap = this.getProperties(); + StringBuilder propertiesString = new StringBuilder(); + if (propertiesMap != null) { + counter = 0; + for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) { + Object ot = entry.getValue(); + String value = ot + ""; + if (ot instanceof String) { + value = "'" + value + "'"; + } else if (ot instanceof Map) { + @SuppressWarnings("unchecked") + Map<String, Object> otMap = (Map<String, Object>) ot; + try { + value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}"; + } catch (Exception e) { + throw new MusicQueryException(e.getMessage(), + Status.BAD_REQUEST.getStatusCode()); + } + } + + propertiesString.append(entry.getKey() + "=" + value + ""); + if (counter != propertiesMap.size() - 1) + propertiesString.append(" AND "); + + counter = counter + 1; + } + } + + String clusteringOrder = this.getClusteringOrder(); + + if (clusteringOrder != null && !(clusteringOrder.isEmpty())) { + String[] arrayClusterOrder = clusteringOrder.split("[,]+"); + + for (int i = 0; i < arrayClusterOrder.length; i++) { + String[] clusterS = arrayClusterOrder[i].trim().split("[ ]+"); + if ( (clusterS.length ==2) && (clusterS[1].equalsIgnoreCase("ASC") || clusterS[1].equalsIgnoreCase("DESC"))) { + continue; + } else { + /*return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname order; please correct clusteringOrder:"+ clusteringOrder+".") + .toMap()).build();*/ + + throw new MusicQueryException( + "createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname order; please correct clusteringOrder:" + + clusteringOrder + ".", + Status.BAD_REQUEST.getStatusCode()); + } + // add validation for column names in cluster key + } + + if (!(clusterKey.isEmpty())) { + clusteringOrder = "CLUSTERING ORDER BY (" +clusteringOrder +")"; + //cjc check if propertiesString.length() >0 instead propertiesMap + if (propertiesMap != null) { + propertiesString.append(" AND "+ clusteringOrder); + } else { + propertiesString.append(clusteringOrder); + } + } else { + logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty "); + } + } //if non empty + + queryObject.appendQueryString( + "CREATE TABLE " + this.getKeyspaceName() + "." + this.getTableName() + " " + fieldsString); + + + if (propertiesString != null && propertiesString.length()>0 ) + queryObject.appendQueryString(" WITH " + propertiesString); + queryObject.appendQueryString(";"); + + return queryObject; + } + + /** + * genDropTableQuery + * + * @return PreparedQueryObject + */ + public PreparedQueryObject genDropTableQuery() { + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString("DROP TABLE " + this.getKeyspaceName() + "." + this.getTableName() + ";"); + logger.info("Delete Query ::::: " + query.getQuery()); + + return query; + } + + +} diff --git a/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java new file mode 100644 index 00000000..29fdb1d4 --- /dev/null +++ b/music-core/src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java @@ -0,0 +1,436 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * 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.datastore.jsonobjects; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.Condition; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ReturnType; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.TableMetadata; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "JsonTable", description = "Json model for table update") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonUpdate implements Serializable { + private String keyspaceName; + private String tableName; + private transient Map<String, Object> values; + private String ttl; + private String timestamp; + private Map<String, String> consistencyInfo; + private transient Map<String, Object> conditions; + private transient Map<String, Object> rowSpecification; + private String rowIdString; + private String primarKeyValue; + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonUpdate.class); + + @ApiModelProperty(value = "Conditions") + public Map<String, Object> getConditions() { + return conditions; + } + + public void setConditions(Map<String, Object> conditions) { + this.conditions = conditions; + } + + @ApiModelProperty(value = "Information for selecting sepcific rows") + public Map<String, Object> getRow_specification() { + return rowSpecification; + } + + public void setRow_specification(Map<String, Object> rowSpecification) { + this.rowSpecification = rowSpecification; + } + + + @ApiModelProperty(value = "Keyspace name") + public String getKeyspaceName() { + return keyspaceName; + } + + public void setKeyspaceName(String keyspaceName) { + this.keyspaceName = keyspaceName; + } + + @ApiModelProperty(value = "Table name") + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic") + public Map<String, String> getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map<String, String> consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + @ApiModelProperty(value = "Time to live value") + public String getTtl() { + return ttl; + } + + public void setTtl(String ttl) { + this.ttl = ttl; + } + + @ApiModelProperty(value = "Time stamp") + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + @ApiModelProperty(value = "Column values") + public Map<String, Object> getValues() { + return values; + } + + public void setValues(Map<String, Object> values) { + this.values = values; + } + + public String getRowIdString() { + return rowIdString; + } + + public void setRowIdString(String rowIdString) { + this.rowIdString = rowIdString; + } + + public String getPrimarKeyValue() { + return primarKeyValue; + } + + public void setPrimarKeyValue(String primarKeyValue) { + this.primarKeyValue = primarKeyValue; + } + + public byte[] serialize() { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutput out = null; + try { + out = new ObjectOutputStream(bos); + out.writeObject(this); + } catch (IOException e) { + logger.error(EELFLoggerDelegate.errorLogger, e,AppMessages.IOERROR, ErrorSeverity.ERROR, ErrorTypes.DATAERROR); + } + return bos.toByteArray(); + } + + /** + * Generate TableInsertQuery + * @return + * @throws MusicQueryException + */ + public PreparedQueryObject genUpdatePreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + + if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty()) || + (this.getTableName() == null || this.getTableName().isEmpty())){ + + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build();*/ + + throw new MusicQueryException("one or more path parameters are not set, please check and try again", + Status.BAD_REQUEST.getStatusCode()); + } + + EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) "); + String operationId = UUID.randomUUID().toString(); // just for infoging purposes. + String consistency = this.getConsistencyInfo().get("type"); + + logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency + + " update-" + operationId + "-------------------------"); + // obtain the field value pairs of the update + + Map<String, Object> valuesMap = this.getValues(); + + TableMetadata tableInfo = getColumnMetadata(this.getKeyspaceName(), this.getTableName()); + + if (tableInfo == null) { + logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+this.getTableName(), AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR); + + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("Table information not found. Please check input for table name= " + + this.getKeyspaceName() + "." + this.getTableName()).toMap()).build();*/ + + throw new MusicQueryException("Table information not found. Please check input for table name= " + + this.getKeyspaceName() + "." + this.getTableName(), Status.BAD_REQUEST.getStatusCode()); + } + + String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + StringBuilder fieldValueString = new StringBuilder("vector_ts=?,"); + queryObject.addValue(vectorTs); + int counter = 0; + for (Map.Entry<String, Object> entry : valuesMap.entrySet()) { + Object valueObj = entry.getValue(); + DataType colType = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + } catch(NullPointerException ex) { + logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey(), ex); + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE). + * setError("Invalid column name : "+entry.getKey()).toMap()).build();*/ + + throw new MusicQueryException("Invalid column name : " + entry.getKey(),Status.BAD_REQUEST.getStatusCode()); + } + Object valueString = null; + try { + valueString = MusicUtil.convertToActualDataType(colType, valueObj); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + fieldValueString.append(entry.getKey() + "= ?"); + queryObject.addValue(valueString); + if (counter != valuesMap.size() - 1) { + fieldValueString.append(","); + } + counter = counter + 1; + } + String ttl = this.getTtl(); + String timestamp = this.getTimestamp(); + + queryObject.appendQueryString("UPDATE " + this.getKeyspaceName() + "." + this.getTableName() + " "); + if ((ttl != null) && (timestamp != null)) { + logger.info("both there"); + queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?"); + queryObject.addValue(Integer.parseInt(ttl)); + queryObject.addValue(Long.parseLong(timestamp)); + } + + if ((ttl != null) && (timestamp == null)) { + logger.info("ONLY TTL there"); + queryObject.appendQueryString(" USING TTL ?"); + queryObject.addValue(Integer.parseInt(ttl)); + } + + if ((ttl == null) && (timestamp != null)) { + logger.info("ONLY timestamp there"); + queryObject.appendQueryString(" USING TIMESTAMP ?"); + queryObject.addValue(Long.parseLong(timestamp)); + } + + // get the row specifier + RowIdentifier rowId = null; + try { + rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject); + this.setRowIdString(rowId.rowIdString); + this.setPrimarKeyValue(rowId.primarKeyValue); + if(rowId == null || rowId.getPrimaryKeyValue().isEmpty()) { + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();*/ + + throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.", + Status.BAD_REQUEST.getStatusCode()); + } + } catch (MusicQueryException ex) { + throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.", + Status.BAD_REQUEST.getStatusCode()); + + }catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes + .GENERALSERVICEERROR, ex); + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();*/ + + throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode()); + + } + + + + queryObject.appendQueryString( + " SET " + fieldValueString + " WHERE " + rowId.getRowIdString() + ";"); + + + + // get the conditional, if any + Condition conditionInfo; + if (this.getConditions() == null) { + conditionInfo = null; + } else { + // to avoid parsing repeatedly, just send the select query to obtain row + PreparedQueryObject selectQuery = new PreparedQueryObject(); + selectQuery.appendQueryString("SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + + rowId.getRowIdString() + ";"); + selectQuery.addValue(rowId.primarKeyValue); + conditionInfo = new Condition(this.getConditions(), selectQuery); + } + + if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) { + if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) { + queryObject.setConsistency(this.getConsistencyInfo().get("consistency")); + } else { + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR) + .setError("Invalid Consistency type").toMap()).build();*/ + + logger.error("Invalid Consistency type"); + throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode()); + } + } + + queryObject.setOperation("update"); + + return queryObject; + } + + TableMetadata getColumnMetadata(String keyspaceName, String tableName) throws MusicQueryException { + TableMetadata tableInfo; + try { + tableInfo = returnColumnMetadata(keyspaceName, tableName); + } catch (MusicServiceException e) { + logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes + .GENERALSERVICEERROR, e); + /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();*/ + throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode()); + }catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR, ErrorSeverity.CRITICAL, + ErrorTypes.GENERALSERVICEERROR); + throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode()); + } + return tableInfo; + } + + /** wrapper around static method for testing */ + TableMetadata returnColumnMetadata(String keyspace, String tableName) throws MusicServiceException { + return MusicDataStoreHandle.returnColumnMetadata(keyspace, tableName); + } + + class RowIdentifier { + private String primarKeyValue; + private String rowIdString; + @SuppressWarnings("unused") + public PreparedQueryObject queryObject; // the string with all the row + // identifiers separated by AND + + public RowIdentifier(String primaryKeyValue, String rowIdString, + PreparedQueryObject queryObject) { + this.primarKeyValue = primaryKeyValue; + this.rowIdString = rowIdString; + this.queryObject = queryObject; + } + + public String getPrimaryKeyValue() { + return this.primarKeyValue; + } + + public void setPrimaryKeyValue(String primaryKeyValue) { + this.primarKeyValue = primaryKeyValue; + } + + public String getRowIdString() { + return this.rowIdString; + } + + public void setRowIdString(String rowIdString) { + this.rowIdString = rowIdString; + } + + public PreparedQueryObject getQueryObject() { + return this.queryObject; + } + } + + /** + * + * @param keyspace + * @param tablename + * @param rowParams + * @param queryObject + * @return + * @throws MusicServiceException + */ + RowIdentifier getRowIdentifier(String keyspace, String tablename, + MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject) + throws MusicServiceException { + StringBuilder rowSpec = new StringBuilder(); + int counter = 0; + TableMetadata tableInfo = returnColumnMetadata(keyspace, tablename); + if (tableInfo == null) { + logger.error(EELFLoggerDelegate.errorLogger, + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + throw new MusicServiceException( + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + } + StringBuilder primaryKey = new StringBuilder(); + for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) { + String keyName = entry.getKey(); + List<String> valueList = entry.getValue(); + String indValue = valueList.get(0); + DataType colType = null; + Object formattedValue = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + formattedValue = MusicUtil.convertToActualDataType(colType, indValue); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) { + primaryKey.append(indValue); + } + rowSpec.append(keyName + "= ?"); + queryObject.addValue(formattedValue); + if (counter != rowParams.size() - 1) { + rowSpec.append(" AND "); + } + counter = counter + 1; + } + return new RowIdentifier(primaryKey.toString(), rowSpec.toString(), queryObject); + } + +} |