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 long startTime = System.currentTimeMillis();
194 String operationId = UUID.randomUUID().toString(); // just for infoging purposes.
195 String consistency = this.getConsistencyInfo().get("type");
197 logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
198 + " update-" + operationId + "-------------------------");
199 // obtain the field value pairs of the update
201 Map<String, Object> valuesMap = this.getValues();
203 TableMetadata tableInfo = getColumnMetadata(this.getKeyspaceName(), this.getTableName());
205 if (tableInfo == null) {
206 logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+this.getTableName(), AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
208 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
209 .setError("Table information not found. Please check input for table name= "
210 + this.getKeyspaceName() + "." + this.getTableName()).toMap()).build();*/
212 throw new MusicQueryException("Table information not found. Please check input for table name= "
213 + this.getKeyspaceName() + "." + this.getTableName(), Status.BAD_REQUEST.getStatusCode());
216 String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
217 StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
218 queryObject.addValue(vectorTs);
220 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
221 Object valueObj = entry.getValue();
222 DataType colType = null;
224 colType = tableInfo.getColumn(entry.getKey()).getType();
225 } catch(NullPointerException ex) {
226 logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey(), ex);
227 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).
228 * setError("Invalid column name : "+entry.getKey()).toMap()).build();*/
230 throw new MusicQueryException("Invalid column name : " + entry.getKey(),Status.BAD_REQUEST.getStatusCode());
232 Object valueString = null;
234 valueString = MusicUtil.convertToActualDataType(colType, valueObj);
235 } catch (Exception e) {
236 logger.error(EELFLoggerDelegate.errorLogger,e);
238 fieldValueString.append(entry.getKey() + "= ?");
239 queryObject.addValue(valueString);
240 if (counter != valuesMap.size() - 1) {
241 fieldValueString.append(",");
243 counter = counter + 1;
245 String ttl = this.getTtl();
246 String timestamp = this.getTimestamp();
248 queryObject.appendQueryString("UPDATE " + this.getKeyspaceName() + "." + this.getTableName() + " ");
249 if ((ttl != null) && (timestamp != null)) {
250 logger.info("both there");
251 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
252 queryObject.addValue(Integer.parseInt(ttl));
253 queryObject.addValue(Long.parseLong(timestamp));
256 if ((ttl != null) && (timestamp == null)) {
257 logger.info("ONLY TTL there");
258 queryObject.appendQueryString(" USING TTL ?");
259 queryObject.addValue(Integer.parseInt(ttl));
262 if ((ttl == null) && (timestamp != null)) {
263 logger.info("ONLY timestamp there");
264 queryObject.appendQueryString(" USING TIMESTAMP ?");
265 queryObject.addValue(Long.parseLong(timestamp));
268 // get the row specifier
269 RowIdentifier rowId = null;
271 rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject);
272 this.setRowIdString(rowId.rowIdString);
273 this.setPrimarKeyValue(rowId.primarKeyValue);
274 if(rowId == null || rowId.getPrimaryKeyValue().isEmpty()) {
275 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
276 .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();*/
278 throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.",
279 Status.BAD_REQUEST.getStatusCode());
281 } catch (MusicQueryException ex) {
282 throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.",
283 Status.BAD_REQUEST.getStatusCode());
285 }catch (MusicServiceException ex) {
286 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
287 .GENERALSERVICEERROR, ex);
288 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();*/
290 throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode());
296 queryObject.appendQueryString(
297 " SET " + fieldValueString + " WHERE " + rowId.getRowIdString() + ";");
301 // get the conditional, if any
302 Condition conditionInfo;
303 if (this.getConditions() == null) {
304 conditionInfo = null;
306 // to avoid parsing repeatedly, just send the select query to obtain row
307 PreparedQueryObject selectQuery = new PreparedQueryObject();
308 selectQuery.appendQueryString("SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE "
309 + rowId.getRowIdString() + ";");
310 selectQuery.addValue(rowId.primarKeyValue);
311 conditionInfo = new Condition(this.getConditions(), selectQuery);
314 ReturnType operationResult = null;
315 long jsonParseCompletionTime = System.currentTimeMillis();
317 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) {
318 if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) {
319 queryObject.setConsistency(this.getConsistencyInfo().get("consistency"));
321 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR)
322 .setError("Invalid Consistency type").toMap()).build();*/
324 logger.error("Invalid Consistency type");
325 throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode());
329 queryObject.setOperation("update");
334 TableMetadata getColumnMetadata(String keyspaceName, String tableName) throws MusicQueryException {
335 TableMetadata tableInfo;
337 tableInfo = returnColumnMetadata(keyspaceName, tableName);
338 } catch (MusicServiceException e) {
339 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
340 .GENERALSERVICEERROR, e);
341 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();*/
342 throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode());
343 }catch (Exception e) {
344 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR, ErrorSeverity.CRITICAL,
345 ErrorTypes.GENERALSERVICEERROR);
346 throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode());
351 /** wrapper around static method for testing */
352 TableMetadata returnColumnMetadata(String keyspace, String tableName) throws MusicServiceException {
353 return MusicDataStoreHandle.returnColumnMetadata(keyspace, tableName);
356 class RowIdentifier {
357 private String primarKeyValue;
358 private String rowIdString;
359 @SuppressWarnings("unused")
360 public PreparedQueryObject queryObject; // the string with all the row
361 // identifiers separated by AND
363 public RowIdentifier(String primaryKeyValue, String rowIdString,
364 PreparedQueryObject queryObject) {
365 this.primarKeyValue = primaryKeyValue;
366 this.rowIdString = rowIdString;
367 this.queryObject = queryObject;
370 public String getPrimaryKeyValue() {
371 return this.primarKeyValue;
374 public void setPrimaryKeyValue(String primaryKeyValue) {
375 this.primarKeyValue = primaryKeyValue;
378 public String getRowIdString() {
379 return this.rowIdString.toString();
382 public void setRowIdString(String rowIdString) {
383 this.rowIdString = rowIdString;
386 public PreparedQueryObject getQueryObject() {
387 return this.queryObject;
398 * @throws MusicServiceException
400 RowIdentifier getRowIdentifier(String keyspace, String tablename,
401 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
402 throws MusicServiceException {
403 StringBuilder rowSpec = new StringBuilder();
405 TableMetadata tableInfo = returnColumnMetadata(keyspace, tablename);
406 if (tableInfo == null) {
407 logger.error(EELFLoggerDelegate.errorLogger,
408 "Table information not found. Please check input for table name= "
409 + keyspace + "." + tablename);
410 throw new MusicServiceException(
411 "Table information not found. Please check input for table name= "
412 + keyspace + "." + tablename);
414 StringBuilder primaryKey = new StringBuilder();
415 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
416 String keyName = entry.getKey();
417 List<String> valueList = entry.getValue();
418 String indValue = valueList.get(0);
419 DataType colType = null;
420 Object formattedValue = null;
422 colType = tableInfo.getColumn(entry.getKey()).getType();
423 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
424 } catch (Exception e) {
425 logger.error(EELFLoggerDelegate.errorLogger,e);
427 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
428 primaryKey.append(indValue);
430 rowSpec.append(keyName + "= ?");
431 queryObject.addValue(formattedValue);
432 if (counter != rowParams.size() - 1) {
433 rowSpec.append(" AND ");
435 counter = counter + 1;
437 return new RowIdentifier(primaryKey.toString(), rowSpec.toString(), queryObject);