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 throw new MusicQueryException("Table name doesn't exists. Please check the table name.",
188 Status.BAD_REQUEST.getStatusCode());
190 } catch (MusicServiceException e) {
191 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
192 throw new MusicQueryException(e.getMessage(),Status.BAD_REQUEST.getStatusCode());
195 String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
196 StringBuilder fieldsString = new StringBuilder("(vector_ts,");
198 String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
199 StringBuilder valueString = new StringBuilder("(" + "?" + ",");
200 queryObject.addValue(vectorTs);
202 Map<String, Object> valuesMap = this.getValues();
203 if (valuesMap==null) {
204 throw new MusicQueryException("Nothing to insert. No values provided in request.",
205 Status.BAD_REQUEST.getStatusCode());
208 String primaryKey = "";
209 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
210 fieldsString.append("" + entry.getKey());
211 Object valueObj = entry.getValue();
212 if (primaryKeyName.equals(entry.getKey())) {
213 primaryKey = entry.getValue() + "";
214 primaryKey = primaryKey.replace("'", "''");
216 DataType colType = null;
218 colType = tableInfo.getColumn(entry.getKey()).getType();
219 } catch(NullPointerException ex) {
220 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey
221 (), AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex);
222 throw new MusicQueryException("Invalid column name : " + entry.getKey(),
223 Status.BAD_REQUEST.getStatusCode());
226 Object formattedValue = null;
228 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
229 } catch (Exception e) {
230 logger.error(EELFLoggerDelegate.errorLogger,e);
232 valueString.append("?");
234 queryObject.addValue(formattedValue);
236 if (counter == valuesMap.size() - 1) {
237 fieldsString.append(")");
238 valueString.append(")");
240 fieldsString.append(",");
241 valueString.append(",");
243 counter = counter + 1;
247 Map<String, byte[]> objectMap = this.getObjectMap();
248 if(objectMap != null) {
249 for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
251 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
252 valueString.replace(valueString.length()-1, valueString.length(), ",");
254 fieldsString.append("" + entry.getKey());
255 byte[] valueObj = entry.getValue();
256 if (primaryKeyName.equals(entry.getKey())) {
257 primaryKey = entry.getValue() + "";
258 primaryKey = primaryKey.replace("'", "''");
260 DataType colType = tableInfo.getColumn(entry.getKey()).getType();
261 ByteBuffer formattedValue = null;
262 if(colType.toString().toLowerCase().contains("blob")) {
263 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
265 valueString.append("?");
266 queryObject.addValue(formattedValue);
267 counter = counter + 1;
268 fieldsString.append(",");
269 valueString.append(",");
272 this.setPrimaryKeyVal(primaryKey);
273 if(primaryKey == null || primaryKey.length() <= 0) {
274 logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
275 throw new MusicQueryException("Some required partition key parts are missing: " + primaryKeyName,
276 Status.BAD_REQUEST.getStatusCode());
279 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
280 valueString.replace(valueString.length()-1, valueString.length(), ")");
282 queryObject.appendQueryString("INSERT INTO " + this.getKeyspaceName() + "." + this.getTableName() + " "
283 + fieldsString + " VALUES " + valueString);
285 String ttl = this.getTtl();
286 String timestamp = this.getTimestamp();
288 if ((ttl != null) && (timestamp != null)) {
289 logger.info(EELFLoggerDelegate.applicationLogger, "both there");
290 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
291 queryObject.addValue(Integer.parseInt(ttl));
292 queryObject.addValue(Long.parseLong(timestamp));
295 if ((ttl != null) && (timestamp == null)) {
296 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
297 queryObject.appendQueryString(" USING TTL ?");
298 queryObject.addValue(Integer.parseInt(ttl));
301 if ((ttl == null) && (timestamp != null)) {
302 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
303 queryObject.appendQueryString(" USING TIMESTAMP ?");
304 queryObject.addValue(Long.parseLong(timestamp));
307 queryObject.appendQueryString(";");
309 String consistency = this.getConsistencyInfo().get("type");
310 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) {
311 if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) {
312 queryObject.setConsistency(this.getConsistencyInfo().get("consistency"));
314 throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode());
317 queryObject.setOperation("insert");
319 logger.info("Data insert Query ::::: " + queryObject.getQuery());
328 * @throws MusicQueryException
330 public PreparedQueryObject genSelectCriticalPreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException {
332 PreparedQueryObject queryObject = new PreparedQueryObject();
334 if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty())
335 || (this.getTableName() == null || this.getTableName().isEmpty())){
336 throw new MusicQueryException("one or more path parameters are not set, please check and try again",
337 Status.BAD_REQUEST.getStatusCode());
339 EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) ");
340 RowIdentifier rowId = null;
342 rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject);
343 this.setPrimaryKeyVal(rowId.primarKeyValue);
344 } catch (MusicServiceException ex) {
345 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
346 .GENERALSERVICEERROR, ex);
347 throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode());
350 queryObject.appendQueryString(
351 "SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + rowId.rowIdString + ";");
356 private class RowIdentifier {
357 public String primarKeyValue;
358 public StringBuilder rowIdString;
359 @SuppressWarnings("unused")
360 public PreparedQueryObject queryObject; // the string with all the row
361 // identifiers separated by AND
363 public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
364 PreparedQueryObject queryObject) {
365 this.primarKeyValue = primaryKeyValue;
366 this.rowIdString = rowIdString;
367 this.queryObject = queryObject;
378 * @throws MusicServiceException
380 private RowIdentifier getRowIdentifier(String keyspace, String tablename,
381 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
382 throws MusicServiceException {
383 StringBuilder rowSpec = new StringBuilder();
385 TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
386 if (tableInfo == null) {
387 logger.error(EELFLoggerDelegate.errorLogger,
388 "Table information not found. Please check input for table name= "
389 + keyspace + "." + tablename);
390 throw new MusicServiceException(
391 "Table information not found. Please check input for table name= "
392 + keyspace + "." + tablename);
394 StringBuilder primaryKey = new StringBuilder();
395 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
396 String keyName = entry.getKey();
397 List<String> valueList = entry.getValue();
398 String indValue = valueList.get(0);
399 DataType colType = null;
400 Object formattedValue = null;
402 colType = tableInfo.getColumn(entry.getKey()).getType();
403 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
404 } catch (Exception e) {
405 logger.error(EELFLoggerDelegate.errorLogger,e);
407 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
408 primaryKey.append(indValue);
410 rowSpec.append(keyName + "= ?");
411 queryObject.addValue(formattedValue);
412 if (counter != rowParams.size() - 1) {
413 rowSpec.append(" AND ");
415 counter = counter + 1;
417 return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);