69ccd104e14c5cbc5519b7c3bfe41effa6a595c0
[music.git] / src / main / java / org / onap / music / conductor / conditionals / MusicConditional.java
1 /*
2  * ============LICENSE_START==========================================
3  * org.onap.music
4  * ===================================================================
5  *  Copyright (c) 2017 AT&T Intellectual Property
6  * ===================================================================
7  *  Modifications Copyright (C) 2019 IBM.
8  *  Modifications Copyright (c) 2019 Samsung
9  * ===================================================================
10  *  Licensed under the Apache License, Version 2.0 (the "License");
11  *  you may not use this file except in compliance with the License.
12  *  You may obtain a copy of the License at
13  * 
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  * 
16  *  Unless required by applicable law or agreed to in writing, software
17  *  distributed under the License is distributed on an "AS IS" BASIS,
18  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  *  See the License for the specific language governing permissions and
20  *  limitations under the License.
21  * 
22  * ============LICENSE_END=============================================
23  * ====================================================================
24  */
25
26 package org.onap.music.conductor.conditionals;
27
28 import java.io.PrintWriter;
29 import java.io.StringWriter;
30 import java.util.HashMap;
31 import java.util.Map;
32
33 import org.codehaus.jettison.json.JSONObject;
34 import org.onap.music.datastore.MusicDataStoreHandle;
35 import org.onap.music.datastore.PreparedQueryObject;
36 import org.onap.music.eelf.logging.EELFLoggerDelegate;
37 import org.onap.music.eelf.logging.format.AppMessages;
38 import org.onap.music.eelf.logging.format.ErrorSeverity;
39 import org.onap.music.eelf.logging.format.ErrorTypes;
40 import org.onap.music.exceptions.MusicLockingException;
41 import org.onap.music.exceptions.MusicQueryException;
42 import org.onap.music.exceptions.MusicServiceException;
43 import org.onap.music.main.MusicCore;
44 import org.onap.music.main.MusicUtil;
45 import org.onap.music.main.ResultType;
46 import org.onap.music.main.ReturnType;
47 import org.onap.music.rest.RestMusicDataAPI;
48
49 import com.datastax.driver.core.ColumnDefinitions;
50 import com.datastax.driver.core.DataType;
51 import com.datastax.driver.core.ResultSet;
52 import com.datastax.driver.core.Row;
53 import com.datastax.driver.core.TableMetadata;
54
55 public class MusicConditional {
56     private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicDataAPI.class);
57
58     public static ReturnType conditionalInsert(String keyspace, String tablename, String casscadeColumnName,
59             Map<String, Object> casscadeColumnData, String primaryKey, Map<String, Object> valuesMap,
60             Map<String, String> status) throws Exception {
61
62         Map<String, PreparedQueryObject> queryBank = new HashMap<>();
63         TableMetadata tableInfo = null;
64         tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
65         DataType primaryIdType = tableInfo.getPrimaryKey().get(0).getType();
66         String primaryId = tableInfo.getPrimaryKey().get(0).getName();
67         DataType casscadeColumnType = tableInfo.getColumn(casscadeColumnName).getType();
68         String vector = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
69
70         PreparedQueryObject select = new PreparedQueryObject();
71         select.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + " where " + primaryId + " = ?");
72         select.addValue(MusicUtil.convertToActualDataType(primaryIdType, primaryKey));
73         queryBank.put(MusicUtil.SELECT, select);
74
75         PreparedQueryObject update = new PreparedQueryObject();
76         //casscade column values
77         Map<String, String> updateColumnvalues = getValues(true, casscadeColumnData, status);
78         Object formatedValues = MusicUtil.convertToActualDataType(casscadeColumnType, updateColumnvalues);
79         update.appendQueryString("UPDATE " + keyspace + "." + tablename + " SET " + casscadeColumnName + " ="
80                 + casscadeColumnName + " + ? , vector_ts = ?" + " WHERE " + primaryId + " = ? ");
81         update.addValue(formatedValues);
82         update.addValue(MusicUtil.convertToActualDataType(DataType.text(), vector));
83         update.addValue(MusicUtil.convertToActualDataType(primaryIdType, primaryKey));
84         queryBank.put(MusicUtil.UPDATE, update);
85
86
87         //casscade column values
88         Map<String, String> insertColumnvalues = getValues(false, casscadeColumnData, status);
89         formatedValues = MusicUtil.convertToActualDataType(casscadeColumnType, insertColumnvalues);
90         PreparedQueryObject insert = extractQuery(valuesMap, tableInfo, tablename, keyspace, primaryId, primaryKey,casscadeColumnName,formatedValues);
91         queryBank.put(MusicUtil.INSERT, insert);
92         
93         
94         String key = keyspace + "." + tablename + "." + primaryKey;
95         String lockId = MusicCore.createLockReference(key);
96         long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
97         ReturnType lockAcqResult = MusicCore.acquireLockWithLease(key, lockId, leasePeriod);
98
99         try {
100             if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
101                 ReturnType criticalPutResult = conditionalInsertAtomic(lockId, keyspace, tablename, primaryKey,
102                         queryBank);
103                 MusicCore.destroyLockRef(lockId);
104                 if (criticalPutResult.getMessage().contains("insert"))
105                     criticalPutResult
106                             .setMessage("Insert values: ");
107                 else if (criticalPutResult.getMessage().contains("update"))
108                     criticalPutResult
109                             .setMessage("Update values: " + updateColumnvalues);
110                 return criticalPutResult;
111
112             } else {
113                 MusicCore.destroyLockRef(lockId);
114                 return lockAcqResult;
115             }
116         } catch (Exception e) {
117             logger.error(EELFLoggerDelegate.applicationLogger, e);
118             MusicCore.destroyLockRef(lockId);
119             return new ReturnType(ResultType.FAILURE, e.getMessage());
120         }
121
122     }
123
124     public static ReturnType conditionalInsertAtomic(String lockId, String keyspace, String tableName,
125             String primaryKey, Map<String, PreparedQueryObject> queryBank) {
126
127         ResultSet results = null;
128
129         try {
130             String fullyQualifiedKey = keyspace + "." + tableName + "." + primaryKey;
131             ReturnType lockAcqResult = MusicCore.acquireLock(fullyQualifiedKey, lockId);
132             if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
133                 try {
134                     results = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(queryBank.get(MusicUtil.SELECT));
135                 } catch (Exception e) {
136                     logger.error(EELFLoggerDelegate.applicationLogger, e);
137                     return new ReturnType(ResultType.FAILURE, e.getMessage());
138                 }
139                 if (results.all().isEmpty()) {
140                     MusicDataStoreHandle.getDSHandle().executePut(queryBank.get(MusicUtil.INSERT), "critical");
141                     return new ReturnType(ResultType.SUCCESS, "insert");
142                 } else {
143                     MusicDataStoreHandle.getDSHandle().executePut(queryBank.get(MusicUtil.UPDATE), "critical");
144                     return new ReturnType(ResultType.SUCCESS, "update");
145                 }
146             } else {
147                 return new ReturnType(ResultType.FAILURE,
148                         "Cannot perform operation since you are the not the lock holder");
149             }
150
151         } catch (Exception e) {
152             StringWriter sw = new StringWriter();
153             e.printStackTrace(new PrintWriter(sw));
154             String exceptionAsString = sw.toString();
155             logger.error(EELFLoggerDelegate.applicationLogger, e);
156             return new ReturnType(ResultType.FAILURE,
157                     "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n"
158                             + exceptionAsString);
159         }
160
161     }
162
163     public static ReturnType update(Map<String,PreparedQueryObject> queryBank, String keyspace, String tableName, String primaryKey,String primaryKeyValue,String planId,String cascadeColumnName,Map<String,String> cascadeColumnValues) throws MusicLockingException, MusicQueryException, MusicServiceException {
164
165         String key = keyspace + "." + tableName + "." + primaryKeyValue;
166         String lockId = MusicCore.createLockReference(key);
167         long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
168         ReturnType lockAcqResult = MusicCore.acquireLockWithLease(key, lockId, leasePeriod);
169
170         try {
171
172             if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
173                 ReturnType criticalPutResult = updateAtomic(lockId, keyspace, tableName, primaryKey,primaryKeyValue, queryBank,planId,cascadeColumnValues,cascadeColumnName);
174                 MusicCore.destroyLockRef(lockId);
175                 return criticalPutResult;
176             } else {
177                 MusicCore.destroyLockRef(lockId);
178                 return lockAcqResult;
179             }
180
181         } catch (Exception e) {
182             MusicCore.destroyLockRef(lockId);
183             logger.error(EELFLoggerDelegate.applicationLogger, e);
184             return new ReturnType(ResultType.FAILURE, e.getMessage());
185
186         }
187     }
188
189     public static ReturnType updateAtomic(String lockId, String keyspace, String tableName, String primaryKey,String primaryKeyValue,
190             Map<String,PreparedQueryObject> queryBank,String planId,Map<String,String> cascadeColumnValues,String casscadeColumnName) {
191         try {
192             String fullyQualifiedKey = keyspace + "." + tableName + "." + primaryKeyValue;
193             ReturnType lockAcqResult = MusicCore.acquireLock(fullyQualifiedKey, lockId);
194
195             if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
196                 Row row  = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(queryBank.get(MusicUtil.SELECT)).one();
197                 
198                 if(row != null) {
199                     Map<String, String> updatedValues = cascadeColumnUpdateSpecific(row, cascadeColumnValues, casscadeColumnName, planId);
200                     JSONObject json = new JSONObject(updatedValues);
201                     PreparedQueryObject update = new PreparedQueryObject();
202                     String vector_ts = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
203                     update.appendQueryString("UPDATE " + keyspace + "." + tableName + " SET " + casscadeColumnName + "['" + planId
204                             + "'] = ?, vector_ts = ? WHERE " + primaryKey + " = ?");
205                     update.addValue(MusicUtil.convertToActualDataType(DataType.text(), json.toString()));
206                     update.addValue(MusicUtil.convertToActualDataType(DataType.text(), vector_ts));
207                     update.addValue(MusicUtil.convertToActualDataType(DataType.text(), primaryKeyValue));
208                     try {
209                         MusicDataStoreHandle.getDSHandle().executePut(update, "critical");
210                     } catch (Exception ex) {
211                         logger.error(EELFLoggerDelegate.applicationLogger, ex);
212                         return new ReturnType(ResultType.FAILURE, ex.getMessage());
213                     }
214                 }else {
215                     return new ReturnType(ResultType.FAILURE,"Cannot find data related to key: "+primaryKey);
216                 }
217                 MusicDataStoreHandle.getDSHandle().executePut(queryBank.get(MusicUtil.UPSERT), "critical");
218                 return new ReturnType(ResultType.SUCCESS, "update success");
219
220             } else {
221                 return new ReturnType(ResultType.FAILURE,
222                         "Cannot perform operation since you are the not the lock holder");
223             }
224
225         } catch (Exception e) {
226             StringWriter sw = new StringWriter();
227             e.printStackTrace(new PrintWriter(sw));
228             String exceptionAsString = sw.toString();
229             logger.error(EELFLoggerDelegate.applicationLogger, e);
230             return new ReturnType(ResultType.FAILURE,
231                     "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n"
232                             + exceptionAsString);
233         }
234
235     }
236
237     @SuppressWarnings("unchecked")
238     public static Map<String, String> getValues(boolean isExists, Map<String, Object> casscadeColumnData,
239             Map<String, String> status) {
240
241         Map<String, String> returnMap = new HashMap<>();
242         Object key = casscadeColumnData.get("key");
243         String setStatus = "";
244         Map<String, String> value = (Map<String, String>) casscadeColumnData.get("value");
245
246         if (isExists)
247             setStatus = status.get("exists");
248         else
249             setStatus = status.get("nonexists");
250
251         value.put("status", setStatus);
252         JSONObject valueJson = new JSONObject(value);
253         returnMap.put(key.toString(), valueJson.toString());
254         return returnMap;
255
256     }
257     
258     public static PreparedQueryObject extractQuery(Map<String, Object> valuesMap, TableMetadata tableInfo, String tableName,
259             String keySpaceName,String primaryKeyName,String primaryKey,String casscadeColumn,Object casscadeColumnValues) throws Exception {
260
261         PreparedQueryObject queryObject = new PreparedQueryObject();
262         StringBuilder fieldsString = new StringBuilder("(vector_ts"+",");
263         StringBuilder valueString = new StringBuilder("(" + "?" + ",");
264         String vector = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
265         String localPrimaryKey;
266         queryObject.addValue(vector);
267         if(casscadeColumn!=null && casscadeColumnValues!=null) {
268             fieldsString.append(casscadeColumn).append(" ,");
269           valueString.append("?,");
270           queryObject.addValue(casscadeColumnValues);
271         }
272         
273         int counter = 0;
274         for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
275             
276             fieldsString.append(entry.getKey());
277             Object valueObj = entry.getValue();
278             if (primaryKeyName.equals(entry.getKey())) {
279               localPrimaryKey = entry.getValue() + "";
280               localPrimaryKey = localPrimaryKey.replace("'", "''");
281             }
282             DataType colType = null;
283             try {
284                 colType = tableInfo.getColumn(entry.getKey()).getType();
285             } catch(NullPointerException ex) {
286                 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey
287                     (), AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex);
288                
289             }
290
291             Object formattedValue = null;
292             try {
293               formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
294             } catch (Exception e) {
295               logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), e);
296           }
297             
298             valueString.append("?");
299             queryObject.addValue(formattedValue);
300
301             
302             if (counter == valuesMap.size() - 1) {
303                 fieldsString.append(")");
304                 valueString.append(")");
305             } else {
306                 fieldsString.append(",");
307                 valueString.append(",");
308             }
309             counter = counter + 1;
310         }
311         queryObject.appendQueryString("INSERT INTO " + keySpaceName + "." + tableName + " "
312                 + fieldsString + " VALUES " + valueString);
313         return queryObject;
314     }
315     
316     public static Object getColValue(Row row, String colName, DataType colType) {
317         switch (colType.getName()) {
318         case VARCHAR:
319             return row.getString(colName);
320         case UUID:
321             return row.getUUID(colName);
322         case VARINT:
323             return row.getVarint(colName);
324         case BIGINT:
325             return row.getLong(colName);
326         case INT:
327             return row.getInt(colName);
328         case FLOAT:
329             return row.getFloat(colName);
330         case DOUBLE:
331             return row.getDouble(colName);
332         case BOOLEAN:
333             return row.getBool(colName);
334         case MAP:
335             return row.getMap(colName, String.class, String.class);
336         default:
337             return null;
338         }
339     }
340     
341     @SuppressWarnings("unchecked")
342     public static Map<String, String> cascadeColumnUpdateSpecific(Row row, Map<String, String> changeOfStatus,
343             String cascadeColumnName, String planId) {
344
345         ColumnDefinitions colInfo = row.getColumnDefinitions();
346         DataType colType = colInfo.getType(cascadeColumnName);
347         Object columnValue = getColValue(row, cascadeColumnName, colType);
348
349         Map<String, String> finalValues = new HashMap<>();
350         Map<String, String> values = (Map<String, String>) columnValue;
351         if (values != null && values.keySet().contains(planId)) {
352             String valueString = values.get(planId);
353             String tempValueString = valueString.replaceAll("\\{", "").replaceAll("\"", "").replaceAll("\\}", "");
354             String[] elements = tempValueString.split(",");
355             for (String str : elements) {
356                 String[] keyValue = str.split(":");
357                 if ((changeOfStatus.keySet().contains(keyValue[0].replaceAll("\\s", ""))))
358                 keyValue[1] = changeOfStatus.get(keyValue[0].replaceAll("\\s", ""));
359                 finalValues.put(keyValue[0], keyValue[1]);
360             }
361         }
362         return finalValues;
363
364     }
365
366 }