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 StringBuilder 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 StringBuilder getRowIdString() {
149 public void setRowIdString(StringBuilder 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 if (logger.isDebugEnabled()) {
180 logger.debug("Coming inside genUpdatePreparedQueryObj method " + this.getKeyspaceName());
181 logger.debug("Coming inside genUpdatePreparedQueryObj method " + this.getTableName());
184 PreparedQueryObject queryObject = new PreparedQueryObject();
186 if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty()) ||
187 (this.getTableName() == null || this.getTableName().isEmpty())){
189 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
190 .setError("one or more path parameters are not set, please check and try again")
193 throw new MusicQueryException("one or more path parameters are not set, please check and try again",
194 Status.BAD_REQUEST.getStatusCode());
197 EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) ");
198 long startTime = System.currentTimeMillis();
199 String operationId = UUID.randomUUID().toString(); // just for infoging purposes.
200 String consistency = this.getConsistencyInfo().get("type");
202 logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
203 + " update-" + operationId + "-------------------------");
204 // obtain the field value pairs of the update
206 Map<String, Object> valuesMap = this.getValues();
208 TableMetadata tableInfo;
211 tableInfo = MusicDataStoreHandle.returnColumnMetadata(this.getKeyspaceName(), this.getTableName());
212 } catch (MusicServiceException e) {
213 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
214 .GENERALSERVICEERROR, e);
215 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();*/
216 throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode());
217 }catch (Exception e) {
218 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR, ErrorSeverity.CRITICAL,
219 ErrorTypes.GENERALSERVICEERROR);
220 throw new MusicQueryException(e.getMessage(), Status.BAD_REQUEST.getStatusCode());
223 if (tableInfo == null) {
224 logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+this.getTableName(), AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
226 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
227 .setError("Table information not found. Please check input for table name= "
228 + this.getKeyspaceName() + "." + this.getTableName()).toMap()).build();*/
230 throw new MusicQueryException("Table information not found. Please check input for table name= "
231 + this.getKeyspaceName() + "." + this.getTableName(), Status.BAD_REQUEST.getStatusCode());
234 String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
235 StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
236 queryObject.addValue(vectorTs);
238 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
239 Object valueObj = entry.getValue();
240 DataType colType = null;
242 colType = tableInfo.getColumn(entry.getKey()).getType();
243 } catch(NullPointerException ex) {
244 logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey(), ex);
245 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).
246 * setError("Invalid column name : "+entry.getKey()).toMap()).build();*/
248 throw new MusicQueryException("Invalid column name : " + entry.getKey(),Status.BAD_REQUEST.getStatusCode());
250 Object valueString = null;
252 valueString = MusicUtil.convertToActualDataType(colType, valueObj);
253 } catch (Exception e) {
254 logger.error(EELFLoggerDelegate.errorLogger,e);
256 fieldValueString.append(entry.getKey() + "= ?");
257 queryObject.addValue(valueString);
258 if (counter != valuesMap.size() - 1) {
259 fieldValueString.append(",");
261 counter = counter + 1;
263 String ttl = this.getTtl();
264 String timestamp = this.getTimestamp();
266 queryObject.appendQueryString("UPDATE " + this.getKeyspaceName() + "." + this.getTableName() + " ");
267 if ((ttl != null) && (timestamp != null)) {
268 logger.info("both there");
269 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
270 queryObject.addValue(Integer.parseInt(ttl));
271 queryObject.addValue(Long.parseLong(timestamp));
274 if ((ttl != null) && (timestamp == null)) {
275 logger.info("ONLY TTL there");
276 queryObject.appendQueryString(" USING TTL ?");
277 queryObject.addValue(Integer.parseInt(ttl));
280 if ((ttl == null) && (timestamp != null)) {
281 logger.info("ONLY timestamp there");
282 queryObject.appendQueryString(" USING TIMESTAMP ?");
283 queryObject.addValue(Long.parseLong(timestamp));
286 // get the row specifier
287 RowIdentifier rowId = null;
289 rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject);
290 this.setRowIdString(rowId.rowIdString);
291 this.setPrimarKeyValue(rowId.primarKeyValue);
292 if(rowId == null || rowId.primarKeyValue.isEmpty()) {
293 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
294 .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();*/
296 throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.",
297 Status.BAD_REQUEST.getStatusCode());
299 } catch (MusicQueryException ex) {
300 throw new MusicQueryException("Mandatory WHERE clause is missing. Please check the input request.",
301 Status.BAD_REQUEST.getStatusCode());
303 }catch (MusicServiceException ex) {
304 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
305 .GENERALSERVICEERROR, ex);
306 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();*/
308 throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode());
314 queryObject.appendQueryString(
315 " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
319 // get the conditional, if any
320 Condition conditionInfo;
321 if (this.getConditions() == null) {
322 conditionInfo = null;
324 // to avoid parsing repeatedly, just send the select query to obtain row
325 PreparedQueryObject selectQuery = new PreparedQueryObject();
326 selectQuery.appendQueryString("SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE "
327 + rowId.rowIdString + ";");
328 selectQuery.addValue(rowId.primarKeyValue);
329 conditionInfo = new Condition(this.getConditions(), selectQuery);
332 ReturnType operationResult = null;
333 long jsonParseCompletionTime = System.currentTimeMillis();
335 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) {
336 if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) {
337 queryObject.setConsistency(this.getConsistencyInfo().get("consistency"));
339 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR)
340 .setError("Invalid Consistency type").toMap()).build();*/
342 logger.error("Invalid Consistency type");
343 throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode());
347 queryObject.setOperation("update");
352 private class RowIdentifier {
353 public String primarKeyValue;
354 public StringBuilder rowIdString;
355 @SuppressWarnings("unused")
356 public PreparedQueryObject queryObject; // the string with all the row
357 // identifiers separated by AND
359 public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
360 PreparedQueryObject queryObject) {
361 this.primarKeyValue = primaryKeyValue;
362 this.rowIdString = rowIdString;
363 this.queryObject = queryObject;
374 * @throws MusicServiceException
376 private RowIdentifier getRowIdentifier(String keyspace, String tablename,
377 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
378 throws MusicServiceException {
379 StringBuilder rowSpec = new StringBuilder();
381 TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
382 if (tableInfo == null) {
383 logger.error(EELFLoggerDelegate.errorLogger,
384 "Table information not found. Please check input for table name= "
385 + keyspace + "." + tablename);
386 throw new MusicServiceException(
387 "Table information not found. Please check input for table name= "
388 + keyspace + "." + tablename);
390 StringBuilder primaryKey = new StringBuilder();
391 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
392 String keyName = entry.getKey();
393 List<String> valueList = entry.getValue();
394 String indValue = valueList.get(0);
395 DataType colType = null;
396 Object formattedValue = null;
398 colType = tableInfo.getColumn(entry.getKey()).getType();
399 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
400 } catch (Exception e) {
401 logger.error(EELFLoggerDelegate.errorLogger,e);
403 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
404 primaryKey.append(indValue);
406 rowSpec.append(keyName + "= ?");
407 queryObject.addValue(formattedValue);
408 if (counter != rowParams.size() - 1) {
409 rowSpec.append(" AND ");
411 counter = counter + 1;
413 return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);