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.nio.ByteBuffer;
32 import java.util.List;
35 import javax.ws.rs.core.MultivaluedMap;
36 import javax.ws.rs.core.Response.Status;
38 import org.onap.music.datastore.MusicDataStoreHandle;
39 import org.onap.music.datastore.PreparedQueryObject;
40 import org.onap.music.eelf.logging.EELFLoggerDelegate;
41 import org.onap.music.eelf.logging.format.AppMessages;
42 import org.onap.music.eelf.logging.format.ErrorSeverity;
43 import org.onap.music.eelf.logging.format.ErrorTypes;
44 import org.onap.music.exceptions.MusicQueryException;
45 import org.onap.music.exceptions.MusicServiceException;
46 import org.onap.music.main.MusicUtil;
47 import org.onap.music.main.ReturnType;
49 import com.datastax.driver.core.DataType;
50 import com.datastax.driver.core.TableMetadata;
51 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
53 import io.swagger.annotations.ApiModel;
54 import io.swagger.annotations.ApiModelProperty;
56 @ApiModel(value = "InsertTable", description = "Json model for table vlaues insert")
57 @JsonIgnoreProperties(ignoreUnknown = true)
58 public class JsonInsert implements Serializable {
59 private static final long serialVersionUID = 1L;
60 private String keyspaceName;
61 private String tableName;
62 private transient Map<String, Object> values;
64 private String timestamp;
65 private transient Map<String, Object> rowSpecification;
66 private Map<String, String> consistencyInfo;
67 private Map<String, byte[]> objectMap;
68 private String primaryKeyVal;
69 private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonInsert.class);
71 @ApiModelProperty(value = "objectMap",hidden = true)
72 public Map<String, byte[]> getObjectMap() {
76 public void setObjectMap(Map<String, byte[]> objectMap) {
77 this.objectMap = objectMap;
80 @ApiModelProperty(value = "keyspace")
81 public String getKeyspaceName() {
85 public void setKeyspaceName(String keyspaceName) {
86 this.keyspaceName = keyspaceName;
89 @ApiModelProperty(value = "Table name")
90 public String getTableName() {
94 public void setTableName(String tableName) {
95 this.tableName = tableName;
98 @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
99 public Map<String, String> getConsistencyInfo() {
100 return consistencyInfo;
103 public void setConsistencyInfo(Map<String, String> consistencyInfo) {
104 this.consistencyInfo = consistencyInfo;
107 @ApiModelProperty(value = "Columns and tables support an optional "
108 + "expiration period called TTL (time-to-live) in seconds.",
109 notes="TTL precision is one second, which is calculated by the coordinator "
110 + "node. When using TTL, ensure that all nodes in the cluster have synchronized clocks.",allowEmptyValue = true)
111 public String getTtl() {
115 public void setTtl(String ttl) {
119 @ApiModelProperty(value = "Time stamp (epoch_in_microseconds)",
120 notes = "Marks inserted data (write time) with TIMESTAMP. "
121 + "Enter the time since epoch (January 1, 1970) in microseconds."
122 + "By default, the actual time of write is used.", allowEmptyValue = true)
123 public String getTimestamp() {
127 public void setTimestamp(String timestamp) {
128 this.timestamp = timestamp;
131 @ApiModelProperty(value = "Json Object of key/values", notes="Where key is the column name and value is the data value for that column.",
132 example = "{'emp_id': 'df98a3d40cd6','emp_name': 'john',"
133 + "'emp_salary': 50,'address':{'street' : '1 Some way','city' : 'New York'}}")
134 public Map<String, Object> getValues() {
138 public void setValues(Map<String, Object> values) {
139 this.values = values;
142 @ApiModelProperty(value = "Information for selecting specific rows for insert",hidden = true)
143 public Map<String, Object> getRowSpecification() {
144 return rowSpecification;
147 public void setRowSpecification(Map<String, Object> rowSpecification) {
148 this.rowSpecification = rowSpecification;
151 public String getPrimaryKeyVal() {
152 return primaryKeyVal;
155 public void setPrimaryKeyVal(String primaryKeyVal) {
156 this.primaryKeyVal = primaryKeyVal;
159 public byte[] serialize() {
160 ByteArrayOutputStream bos = new ByteArrayOutputStream();
161 ObjectOutput out = null;
163 out = new ObjectOutputStream(bos);
164 out.writeObject(this);
165 } catch (IOException e) {
166 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.IOERROR, ErrorSeverity.ERROR, ErrorTypes.DATAERROR);
168 return bos.toByteArray();
172 * Generate TableInsertQuery
174 * @throws MusicQueryException
176 public PreparedQueryObject genInsertPreparedQueryObj() throws MusicQueryException {
177 if (logger.isDebugEnabled()) {
178 logger.debug("Coming inside genTableInsertQuery method " + this.getKeyspaceName());
179 logger.debug("Coming inside genTableInsertQuery method " + this.getTableName());
182 PreparedQueryObject queryObject = new PreparedQueryObject();
183 TableMetadata tableInfo = null;
185 tableInfo = MusicDataStoreHandle.returnColumnMetadata(this.getKeyspaceName(), this.getTableName());
186 if(tableInfo == null) {
187 //return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Table name doesn't exists. Please check the table name.").toMap()).build();
188 throw new MusicQueryException("Table name doesn't exists. Please check the table name.",
189 Status.BAD_REQUEST.getStatusCode());
191 } catch (MusicServiceException e) {
192 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
193 //return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
194 throw new MusicQueryException(e.getMessage(),Status.BAD_REQUEST.getStatusCode());
197 String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
198 StringBuilder fieldsString = new StringBuilder("(vector_ts,");
200 String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
201 StringBuilder valueString = new StringBuilder("(" + "?" + ",");
202 queryObject.addValue(vectorTs);
204 Map<String, Object> valuesMap = this.getValues();
205 if (valuesMap==null) {
206 //return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
207 //.setError("Nothing to insert. No values provided in request.").toMap()).build();
208 throw new MusicQueryException("Nothing to insert. No values provided in request.",
209 Status.BAD_REQUEST.getStatusCode());
212 String primaryKey = "";
213 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
214 fieldsString.append("" + entry.getKey());
215 Object valueObj = entry.getValue();
216 if (primaryKeyName.equals(entry.getKey())) {
217 primaryKey = entry.getValue() + "";
218 primaryKey = primaryKey.replace("'", "''");
220 DataType colType = null;
222 colType = tableInfo.getColumn(entry.getKey()).getType();
223 } catch(NullPointerException ex) {
224 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey
225 (), AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex);
226 //return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
227 throw new MusicQueryException("Invalid column name : " + entry.getKey(),
228 Status.BAD_REQUEST.getStatusCode());
231 Object formattedValue = null;
233 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
234 } catch (Exception e) {
235 logger.error(EELFLoggerDelegate.errorLogger,e);
237 valueString.append("?");
239 queryObject.addValue(formattedValue);
241 if (counter == valuesMap.size() - 1) {
242 fieldsString.append(")");
243 valueString.append(")");
245 fieldsString.append(",");
246 valueString.append(",");
248 counter = counter + 1;
252 Map<String, byte[]> objectMap = this.getObjectMap();
253 if(objectMap != null) {
254 for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
256 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
257 valueString.replace(valueString.length()-1, valueString.length(), ",");
259 fieldsString.append("" + entry.getKey());
260 byte[] valueObj = entry.getValue();
261 if (primaryKeyName.equals(entry.getKey())) {
262 primaryKey = entry.getValue() + "";
263 primaryKey = primaryKey.replace("'", "''");
265 DataType colType = tableInfo.getColumn(entry.getKey()).getType();
266 ByteBuffer formattedValue = null;
267 if(colType.toString().toLowerCase().contains("blob")) {
268 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
270 valueString.append("?");
271 queryObject.addValue(formattedValue);
272 counter = counter + 1;
273 fieldsString.append(",");
274 valueString.append(",");
277 this.setPrimaryKeyVal(primaryKey);
278 if(primaryKey == null || primaryKey.length() <= 0) {
279 logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
280 //return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Some required partition key parts are missing: "+primaryKeyName).toMap()).build();
281 throw new MusicQueryException("Some required partition key parts are missing: " + primaryKeyName,
282 Status.BAD_REQUEST.getStatusCode());
285 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
286 valueString.replace(valueString.length()-1, valueString.length(), ")");
288 queryObject.appendQueryString("INSERT INTO " + this.getKeyspaceName() + "." + this.getTableName() + " "
289 + fieldsString + " VALUES " + valueString);
291 String ttl = this.getTtl();
292 String timestamp = this.getTimestamp();
294 if ((ttl != null) && (timestamp != null)) {
295 logger.info(EELFLoggerDelegate.applicationLogger, "both there");
296 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
297 queryObject.addValue(Integer.parseInt(ttl));
298 queryObject.addValue(Long.parseLong(timestamp));
301 if ((ttl != null) && (timestamp == null)) {
302 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
303 queryObject.appendQueryString(" USING TTL ?");
304 queryObject.addValue(Integer.parseInt(ttl));
307 if ((ttl == null) && (timestamp != null)) {
308 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
309 queryObject.appendQueryString(" USING TIMESTAMP ?");
310 queryObject.addValue(Long.parseLong(timestamp));
313 queryObject.appendQueryString(";");
315 ReturnType result = null;
316 String consistency = this.getConsistencyInfo().get("type");
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).setError("Invalid Consistency type").toMap()).build();
322 throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode());
325 queryObject.setOperation("insert");
327 logger.info("Data insert Query ::::: " + queryObject.getQuery());
336 * @throws MusicQueryException
338 public PreparedQueryObject genSelectCriticalPreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException {
340 PreparedQueryObject queryObject = new PreparedQueryObject();
342 if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty())
343 || (this.getTableName() == null || this.getTableName().isEmpty())){
344 /* return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
345 .setError("one or more path parameters are not set, please check and try again")
347 throw new MusicQueryException("one or more path parameters are not set, please check and try again",
348 Status.BAD_REQUEST.getStatusCode());
350 EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) ");
351 RowIdentifier rowId = null;
353 rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject);
354 this.setPrimaryKeyVal(rowId.primarKeyValue);
355 } catch (MusicServiceException ex) {
356 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
357 .GENERALSERVICEERROR, ex);
358 /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();*/
359 throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode());
362 queryObject.appendQueryString(
363 "SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + rowId.rowIdString + ";");
368 private class RowIdentifier {
369 public String primarKeyValue;
370 public StringBuilder rowIdString;
371 @SuppressWarnings("unused")
372 public PreparedQueryObject queryObject; // the string with all the row
373 // identifiers separated by AND
375 public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
376 PreparedQueryObject queryObject) {
377 this.primarKeyValue = primaryKeyValue;
378 this.rowIdString = rowIdString;
379 this.queryObject = queryObject;
390 * @throws MusicServiceException
392 private RowIdentifier getRowIdentifier(String keyspace, String tablename,
393 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
394 throws MusicServiceException {
395 StringBuilder rowSpec = new StringBuilder();
397 TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
398 if (tableInfo == null) {
399 logger.error(EELFLoggerDelegate.errorLogger,
400 "Table information not found. Please check input for table name= "
401 + keyspace + "." + tablename);
402 throw new MusicServiceException(
403 "Table information not found. Please check input for table name= "
404 + keyspace + "." + tablename);
406 StringBuilder primaryKey = new StringBuilder();
407 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
408 String keyName = entry.getKey();
409 List<String> valueList = entry.getValue();
410 String indValue = valueList.get(0);
411 DataType colType = null;
412 Object formattedValue = null;
414 colType = tableInfo.getColumn(entry.getKey()).getType();
415 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
416 } catch (Exception e) {
417 logger.error(EELFLoggerDelegate.errorLogger,e);
419 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
420 primaryKey.append(indValue);
422 rowSpec.append(keyName + "= ?");
423 queryObject.addValue(formattedValue);
424 if (counter != rowParams.size() - 1) {
425 rowSpec.append(" AND ");
427 counter = counter + 1;
429 return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);