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;
48 import com.datastax.driver.core.DataType;
49 import com.datastax.driver.core.TableMetadata;
50 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
52 import io.swagger.annotations.ApiModel;
53 import io.swagger.annotations.ApiModelProperty;
55 @ApiModel(value = "InsertTable", description = "Json model for table vlaues insert")
56 @JsonIgnoreProperties(ignoreUnknown = true)
57 public class JsonInsert implements Serializable {
58 private static final long serialVersionUID = 1L;
59 private String keyspaceName;
60 private String tableName;
61 private transient Map<String, Object> values;
63 private String timestamp;
64 private transient Map<String, Object> rowSpecification;
65 private Map<String, String> consistencyInfo;
66 private Map<String, byte[]> objectMap;
67 private String primaryKeyVal;
68 private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonInsert.class);
70 @ApiModelProperty(value = "objectMap",hidden = true)
71 public Map<String, byte[]> getObjectMap() {
75 public void setObjectMap(Map<String, byte[]> objectMap) {
76 this.objectMap = objectMap;
79 @ApiModelProperty(value = "keyspace")
80 public String getKeyspaceName() {
84 public void setKeyspaceName(String keyspaceName) {
85 this.keyspaceName = keyspaceName;
88 @ApiModelProperty(value = "Table name")
89 public String getTableName() {
93 public void setTableName(String tableName) {
94 this.tableName = tableName;
97 @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
98 public Map<String, String> getConsistencyInfo() {
99 return consistencyInfo;
102 public void setConsistencyInfo(Map<String, String> consistencyInfo) {
103 this.consistencyInfo = consistencyInfo;
106 @ApiModelProperty(value = "Columns and tables support an optional "
107 + "expiration period called TTL (time-to-live) in seconds.",
108 notes="TTL precision is one second, which is calculated by the coordinator "
109 + "node. When using TTL, ensure that all nodes in the cluster have synchronized clocks.",allowEmptyValue = true)
110 public String getTtl() {
114 public void setTtl(String ttl) {
118 @ApiModelProperty(value = "Time stamp (epoch_in_microseconds)",
119 notes = "Marks inserted data (write time) with TIMESTAMP. "
120 + "Enter the time since epoch (January 1, 1970) in microseconds."
121 + "By default, the actual time of write is used.", allowEmptyValue = true)
122 public String getTimestamp() {
126 public void setTimestamp(String timestamp) {
127 this.timestamp = timestamp;
130 @ApiModelProperty(value = "Json Object of key/values", notes="Where key is the column name and value is the data value for that column.",
131 example = "{'emp_id': 'df98a3d40cd6','emp_name': 'john',"
132 + "'emp_salary': 50,'address':{'street' : '1 Some way','city' : 'New York'}}")
133 public Map<String, Object> getValues() {
137 public void setValues(Map<String, Object> values) {
138 this.values = values;
141 @ApiModelProperty(value = "Information for selecting specific rows for insert",hidden = true)
142 public Map<String, Object> getRowSpecification() {
143 return rowSpecification;
146 public void setRowSpecification(Map<String, Object> rowSpecification) {
147 this.rowSpecification = rowSpecification;
150 public String getPrimaryKeyVal() {
151 return primaryKeyVal;
154 public void setPrimaryKeyVal(String primaryKeyVal) {
155 this.primaryKeyVal = primaryKeyVal;
158 public byte[] serialize() {
159 ByteArrayOutputStream bos = new ByteArrayOutputStream();
160 ObjectOutput out = null;
162 out = new ObjectOutputStream(bos);
163 out.writeObject(this);
164 } catch (IOException e) {
165 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.IOERROR, ErrorSeverity.ERROR, ErrorTypes.DATAERROR);
167 return bos.toByteArray();
171 * Generate TableInsertQuery
173 * @throws MusicQueryException
175 public PreparedQueryObject genInsertPreparedQueryObj() throws MusicQueryException {
176 if (logger.isDebugEnabled()) {
177 logger.debug("Coming inside genTableInsertQuery method " + this.getKeyspaceName());
178 logger.debug("Coming inside genTableInsertQuery method " + this.getTableName());
181 PreparedQueryObject queryObject = new PreparedQueryObject();
182 TableMetadata tableInfo = null;
184 tableInfo = MusicDataStoreHandle.returnColumnMetadata(this.getKeyspaceName(), this.getTableName());
185 if(tableInfo == null) {
186 throw new MusicQueryException("Table name doesn't exists. Please check the table name.",
187 Status.BAD_REQUEST.getStatusCode());
189 } catch (MusicServiceException e) {
190 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
191 throw new MusicQueryException(e.getMessage(),Status.BAD_REQUEST.getStatusCode());
194 String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
195 StringBuilder fieldsString = new StringBuilder("(vector_ts,");
197 String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
198 StringBuilder valueString = new StringBuilder("(" + "?" + ",");
199 queryObject.addValue(vectorTs);
201 Map<String, Object> valuesMap = this.getValues();
202 if (valuesMap==null) {
203 throw new MusicQueryException("Nothing to insert. No values provided in request.",
204 Status.BAD_REQUEST.getStatusCode());
207 String primaryKey = "";
208 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
209 fieldsString.append("" + entry.getKey());
210 Object valueObj = entry.getValue();
211 if (primaryKeyName.equals(entry.getKey())) {
212 primaryKey = entry.getValue() + "";
213 primaryKey = primaryKey.replace("'", "''");
215 DataType colType = null;
217 colType = tableInfo.getColumn(entry.getKey()).getType();
218 } catch(NullPointerException ex) {
219 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey
220 (), AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex);
221 throw new MusicQueryException("Invalid column name : " + entry.getKey(),
222 Status.BAD_REQUEST.getStatusCode());
225 Object formattedValue = null;
227 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
228 } catch (Exception e) {
229 logger.error(EELFLoggerDelegate.errorLogger,e);
231 valueString.append("?");
233 queryObject.addValue(formattedValue);
235 if (counter == valuesMap.size() - 1) {
236 fieldsString.append(")");
237 valueString.append(")");
239 fieldsString.append(",");
240 valueString.append(",");
242 counter = counter + 1;
246 Map<String, byte[]> objectMap = this.getObjectMap();
247 if(objectMap != null) {
248 for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
250 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
251 valueString.replace(valueString.length()-1, valueString.length(), ",");
253 fieldsString.append("" + entry.getKey());
254 byte[] valueObj = entry.getValue();
255 if (primaryKeyName.equals(entry.getKey())) {
256 primaryKey = entry.getValue() + "";
257 primaryKey = primaryKey.replace("'", "''");
259 DataType colType = tableInfo.getColumn(entry.getKey()).getType();
260 ByteBuffer formattedValue = null;
261 if(colType.toString().toLowerCase().contains("blob")) {
262 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
264 valueString.append("?");
265 queryObject.addValue(formattedValue);
266 counter = counter + 1;
267 fieldsString.append(",");
268 valueString.append(",");
271 this.setPrimaryKeyVal(primaryKey);
272 if(primaryKey == null || primaryKey.length() <= 0) {
273 logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
274 throw new MusicQueryException("Some required partition key parts are missing: " + primaryKeyName,
275 Status.BAD_REQUEST.getStatusCode());
278 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
279 valueString.replace(valueString.length()-1, valueString.length(), ")");
281 queryObject.appendQueryString("INSERT INTO " + this.getKeyspaceName() + "." + this.getTableName() + " "
282 + fieldsString + " VALUES " + valueString);
284 String ttl = this.getTtl();
285 String timestamp = this.getTimestamp();
287 if ((ttl != null) && (timestamp != null)) {
288 logger.info(EELFLoggerDelegate.applicationLogger, "both there");
289 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
290 queryObject.addValue(Integer.parseInt(ttl));
291 queryObject.addValue(Long.parseLong(timestamp));
294 if ((ttl != null) && (timestamp == null)) {
295 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
296 queryObject.appendQueryString(" USING TTL ?");
297 queryObject.addValue(Integer.parseInt(ttl));
300 if ((ttl == null) && (timestamp != null)) {
301 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
302 queryObject.appendQueryString(" USING TIMESTAMP ?");
303 queryObject.addValue(Long.parseLong(timestamp));
306 queryObject.appendQueryString(";");
308 String consistency = this.getConsistencyInfo().get("type");
309 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && this.getConsistencyInfo().get("consistency") != null) {
310 if(MusicUtil.isValidConsistency(this.getConsistencyInfo().get("consistency"))) {
311 queryObject.setConsistency(this.getConsistencyInfo().get("consistency"));
313 throw new MusicQueryException("Invalid Consistency type", Status.BAD_REQUEST.getStatusCode());
316 queryObject.setOperation("insert");
318 logger.info("Data insert Query ::::: " + queryObject.getQuery());
327 * @throws MusicQueryException
329 public PreparedQueryObject genSelectCriticalPreparedQueryObj(MultivaluedMap<String, String> rowParams) throws MusicQueryException {
331 PreparedQueryObject queryObject = new PreparedQueryObject();
333 if((this.getKeyspaceName() == null || this.getKeyspaceName().isEmpty())
334 || (this.getTableName() == null || this.getTableName().isEmpty())){
335 throw new MusicQueryException("one or more path parameters are not set, please check and try again",
336 Status.BAD_REQUEST.getStatusCode());
338 EELFLoggerDelegate.mdcPut("keyspace", "( "+this.getKeyspaceName()+" ) ");
339 RowIdentifier rowId = null;
341 rowId = getRowIdentifier(this.getKeyspaceName(), this.getTableName(), rowParams, queryObject);
342 this.setPrimaryKeyVal(rowId.primarKeyValue);
343 } catch (MusicServiceException ex) {
344 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
345 .GENERALSERVICEERROR, ex);
346 throw new MusicQueryException(ex.getMessage(), Status.BAD_REQUEST.getStatusCode());
349 queryObject.appendQueryString(
350 "SELECT * FROM " + this.getKeyspaceName() + "." + this.getTableName() + " WHERE " + rowId.rowIdString + ";");
355 private class RowIdentifier {
356 public String primarKeyValue;
357 public StringBuilder rowIdString;
358 @SuppressWarnings("unused")
359 public PreparedQueryObject queryObject; // the string with all the row
360 // identifiers separated by AND
362 public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
363 PreparedQueryObject queryObject) {
364 this.primarKeyValue = primaryKeyValue;
365 this.rowIdString = rowIdString;
366 this.queryObject = queryObject;
377 * @throws MusicServiceException
379 private RowIdentifier getRowIdentifier(String keyspace, String tablename,
380 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
381 throws MusicServiceException {
382 StringBuilder rowSpec = new StringBuilder();
384 TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
385 if (tableInfo == null) {
386 logger.error(EELFLoggerDelegate.errorLogger,
387 "Table information not found. Please check input for table name= "
388 + keyspace + "." + tablename);
389 throw new MusicServiceException(
390 "Table information not found. Please check input for table name= "
391 + keyspace + "." + tablename);
393 StringBuilder primaryKey = new StringBuilder();
394 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
395 String keyName = entry.getKey();
396 List<String> valueList = entry.getValue();
397 String indValue = valueList.get(0);
398 DataType colType = null;
399 Object formattedValue = null;
401 colType = tableInfo.getColumn(entry.getKey()).getType();
402 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
403 } catch (Exception e) {
404 logger.error(EELFLoggerDelegate.errorLogger,e);
406 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
407 primaryKey.append(indValue);
409 rowSpec.append(keyName + "= ?");
410 queryObject.addValue(formattedValue);
411 if (counter != rowParams.size() - 1) {
412 rowSpec.append(" AND ");
414 counter = counter + 1;
416 return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);