2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (c) 2017 AT&T Intellectual Property
6 * Modifications Copyright (C) 2019 IBM
7 * ===================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 * ============LICENSE_END=============================================
21 * ====================================================================
24 package org.onap.music.datastore.jsonobjects;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.ObjectOutput;
29 import java.io.ObjectOutputStream;
30 import java.io.Serializable;
31 import java.util.List;
33 import java.util.UUID;
35 import javax.ws.rs.core.MultivaluedMap;
36 import javax.ws.rs.core.Response.Status;
38 import org.onap.music.datastore.Condition;
39 import org.onap.music.datastore.MusicDataStoreHandle;
40 import org.onap.music.datastore.PreparedQueryObject;
41 import org.onap.music.eelf.logging.EELFLoggerDelegate;
42 import org.onap.music.eelf.logging.format.AppMessages;
43 import org.onap.music.eelf.logging.format.ErrorSeverity;
44 import org.onap.music.eelf.logging.format.ErrorTypes;
45 import org.onap.music.exceptions.MusicQueryException;
46 import org.onap.music.exceptions.MusicServiceException;
47 import org.onap.music.main.MusicUtil;
48 import org.onap.music.main.ReturnType;
50 import com.datastax.driver.core.DataType;
51 import com.datastax.driver.core.TableMetadata;
52 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
54 import io.swagger.annotations.ApiModel;
55 import io.swagger.annotations.ApiModelProperty;
57 @ApiModel(value = "JsonTable", description = "Json model for table update")
58 @JsonIgnoreProperties(ignoreUnknown = true)
59 public class JsonUpdate implements Serializable {
60 private String keyspaceName;
61 private String tableName;
62 private transient Map<String, Object> values;
64 private String timestamp;
65 private Map<String, String> consistencyInfo;
66 private transient Map<String, Object> conditions;
67 private transient Map<String, Object> rowSpecification;
68 private String rowIdString;
69 private String primarKeyValue;
70 private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonUpdate.class);
72 @ApiModelProperty(value = "Conditions")
73 public Map<String, Object> getConditions() {
77 public void setConditions(Map<String, Object> conditions) {
78 this.conditions = conditions;
81 @ApiModelProperty(value = "Information for selecting sepcific rows")
82 public Map<String, Object> getRow_specification() {
83 return rowSpecification;
86 public void setRow_specification(Map<String, Object> rowSpecification) {
87 this.rowSpecification = rowSpecification;
91 @ApiModelProperty(value = "Keyspace name")
92 public String getKeyspaceName() {
96 public void setKeyspaceName(String keyspaceName) {
97 this.keyspaceName = keyspaceName;
100 @ApiModelProperty(value = "Table name")
101 public String getTableName() {
105 public void setTableName(String tableName) {
106 this.tableName = tableName;
109 @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
110 public Map<String, String> getConsistencyInfo() {
111 return consistencyInfo;
114 public void setConsistencyInfo(Map<String, String> consistencyInfo) {
115 this.consistencyInfo = consistencyInfo;
118 @ApiModelProperty(value = "Time to live value")
119 public String getTtl() {
123 public void setTtl(String ttl) {
127 @ApiModelProperty(value = "Time stamp")
128 public String getTimestamp() {
132 public void setTimestamp(String timestamp) {
133 this.timestamp = timestamp;
136 @ApiModelProperty(value = "Column values")
137 public Map<String, Object> getValues() {
141 public void setValues(Map<String, Object> values) {
142 this.values = values;
145 public String getRowIdString() {
149 public void setRowIdString(String rowIdString) {
150 this.rowIdString = rowIdString;
153 public String getPrimarKeyValue() {
154 return primarKeyValue;
157 public void setPrimarKeyValue(String primarKeyValue) {
158 this.primarKeyValue = primarKeyValue;
161 public byte[] serialize() {
162 ByteArrayOutputStream bos = new ByteArrayOutputStream();
163 ObjectOutput out = null;
165 out = new ObjectOutputStream(bos);
166 out.writeObject(this);
167 } catch (IOException e) {
168 logger.error(EELFLoggerDelegate.errorLogger, e,AppMessages.IOERROR, ErrorSeverity.ERROR, ErrorTypes.DATAERROR);
170 return bos.toByteArray();
174 * Generate TableInsertQuery
176 * @throws MusicQueryException
178 public PreparedQueryObject genUpdatePreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException {
179 PreparedQueryObject queryObject = new PreparedQueryObject();
181 if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty()) ||
182 (this.getTableName() == null || this.getTableName().isEmpty())){
184 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
185 .setError("one or more path parameters are not set, please check and try again")
188 throw new MusicQueryException("one or more path parameters are not set, please check and try again",
189 Status.BAD_REQUEST.getStatusCode());
192 EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) ");
193 String operationId = UUID.randomUUID().toString(); // just for infoging purposes.
194 String consistency = this.getConsistencyInfo().get("type");
196 logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
197 + " update-" + operationId + "-------------------------");
198 // obtain the field value pairs of the update
200 Map<String, Object> valuesMap = this.getValues();
202 TableMetadata tableInfo = getColumnMetadata(this.getKeyspaceName(), this.getTableName());
204 if (tableInfo == null) {
205 logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+this.getTableName(), AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
207 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
208 .setError("Table information not found. Please check input for table name= "
209 + this.getKeyspaceName() + "." + this.getTableName()).toMap()).build();*/
211 throw new MusicQueryException("Table information not found. Please check input for table name= "
212 + this.getKeyspaceName() + "." + this.getTableName(), Status.BAD_REQUEST.getStatusCode());
215 String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
216 StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
217 queryObject.addValue(vectorTs);
219 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
220 Object valueObj = entry.getValue();
221 DataType colType = null;
223 colType = tableInfo.getColumn(entry.getKey()).getType();
224 } catch(NullPointerException ex) {
225 logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey(), ex);
226 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).
227 * setError("Invalid column name : "+entry.getKey()).toMap()).build();*/
229 throw new MusicQueryException("Invalid column name : " + entry.getKey(),Status.BAD_REQUEST.getStatusCode());
231 Object valueString = null;
233 valueString = MusicUtil.convertToActualDataType(colType, valueObj);
234 } catch (Exception e) {
235 logger.error(EELFLoggerDelegate.errorLogger,e);
237 fieldValueString.append(entry.getKey() + "= ?");
238 queryObject.addValue(valueString);
239 if (counter != valuesMap.size() - 1) {
240 fieldValueString.append(",");
242 counter = counter + 1;
244 String ttl = this.getTtl();
245 String timestamp = this.getTimestamp();
247 queryObject.appendQueryString("UPDATE " + this.getKeyspaceName() + "." + this.getTableName() + " ");
248 if ((ttl != null) && (timestamp != null)) {
249 logger.info("both there");
250 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
251 queryObject.addValue(Integer.parseInt(ttl));
252 queryObject.addValue(Long.parseLong(timestamp));
255 if ((ttl != null) && (timestamp == null)) {
256 logger.info("ONLY TTL there");
257 queryObject.appendQueryString(" USING TTL ?");
258 queryObject.addValue(Integer.parseInt(ttl));
261 if ((ttl == null) && (timestamp != null)) {
262 logger.info("ONLY timestamp there");
263 queryObject.appendQueryString(" USING TIMESTAMP ?");
264 queryObject.addValue(Long.parseLong(timestamp));
267 // get the row specifier
268 RowIdentifier rowId = null;
270 rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject);
271 this.setRowIdString(rowId.rowIdString);
272 this.setPrimarKeyValue(rowId.primarKeyValue);
273 if(rowId == null || rowId.getPrimaryKeyValue().isEmpty()) {
274 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
275 .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();*/
277 throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.",
278 Status.BAD_REQUEST.getStatusCode());
280 } catch (MusicQueryException ex) {
281 throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.",
282 Status.BAD_REQUEST.getStatusCode());
284 }catch (MusicServiceException ex) {
285 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
286 .GENERALSERVICEERROR, ex);
287 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();*/
289 throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode());
295 queryObject.appendQueryString(
296 " SET " + fieldValueString + " WHERE " + rowId.getRowIdString() + ";");
300 // get the conditional, if any
301 Condition conditionInfo;
302 if (this.getConditions() == null) {
303 conditionInfo = null;
305 // to avoid parsing repeatedly, just send the select query to obtain row
306 PreparedQueryObject selectQuery = new PreparedQueryObject();
307 selectQuery.appendQueryString("SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE "
308 + rowId.getRowIdString() + ";");
309 selectQuery.addValue(rowId.primarKeyValue);
310 conditionInfo = new Condition(this.getConditions(), selectQuery);
313 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) {
314 if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) {
315 queryObject.setConsistency(this.getConsistencyInfo().get("consistency"));
317 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR)
318 .setError("Invalid Consistency type").toMap()).build();*/
320 logger.error("Invalid Consistency type");
321 throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode());
325 queryObject.setOperation("update");
330 TableMetadata getColumnMetadata(String keyspaceName, String tableName) throws MusicQueryException {
331 TableMetadata tableInfo;
333 tableInfo = returnColumnMetadata(keyspaceName, tableName);
334 } catch (MusicServiceException e) {
335 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
336 .GENERALSERVICEERROR, e);
337 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();*/
338 throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode());
339 }catch (Exception e) {
340 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR, ErrorSeverity.CRITICAL,
341 ErrorTypes.GENERALSERVICEERROR);
342 throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode());
347 /** wrapper around static method for testing */
348 TableMetadata returnColumnMetadata(String keyspace, String tableName) throws MusicServiceException {
349 return MusicDataStoreHandle.returnColumnMetadata(keyspace, tableName);
352 class RowIdentifier {
353 private String primarKeyValue;
354 private String rowIdString;
355 @SuppressWarnings("unused")
356 public PreparedQueryObject queryObject; // the string with all the row
357 // identifiers separated by AND
359 public RowIdentifier(String primaryKeyValue, String rowIdString,
360 PreparedQueryObject queryObject) {
361 this.primarKeyValue = primaryKeyValue;
362 this.rowIdString = rowIdString;
363 this.queryObject = queryObject;
366 public String getPrimaryKeyValue() {
367 return this.primarKeyValue;
370 public void setPrimaryKeyValue(String primaryKeyValue) {
371 this.primarKeyValue = primaryKeyValue;
374 public String getRowIdString() {
375 return this.rowIdString;
378 public void setRowIdString(String rowIdString) {
379 this.rowIdString = rowIdString;
382 public PreparedQueryObject getQueryObject() {
383 return this.queryObject;
394 * @throws MusicServiceException
396 RowIdentifier getRowIdentifier(String keyspace, String tablename,
397 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
398 throws MusicServiceException {
399 StringBuilder rowSpec = new StringBuilder();
401 TableMetadata tableInfo = returnColumnMetadata(keyspace, tablename);
402 if (tableInfo == null) {
403 logger.error(EELFLoggerDelegate.errorLogger,
404 "Table information not found. Please check input for table name= "
405 + keyspace + "." + tablename);
406 throw new MusicServiceException(
407 "Table information not found. Please check input for table name= "
408 + keyspace + "." + tablename);
410 StringBuilder primaryKey = new StringBuilder();
411 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
412 String keyName = entry.getKey();
413 List<String> valueList = entry.getValue();
414 String indValue = valueList.get(0);
415 DataType colType = null;
416 Object formattedValue = null;
418 colType = tableInfo.getColumn(entry.getKey()).getType();
419 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
420 } catch (Exception e) {
421 logger.error(EELFLoggerDelegate.errorLogger,e);
423 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
424 primaryKey.append(indValue);
426 rowSpec.append(keyName + "= ?");
427 queryObject.addValue(formattedValue);
428 if (counter != rowParams.size() - 1) {
429 rowSpec.append(" AND ");
431 counter = counter + 1;
433 return new RowIdentifier(primaryKey.toString(), rowSpec.toString(), queryObject);