2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (c) 2017 AT&T Intellectual Property
6 * ===================================================================
7 * Modifications Copyright (c) 2019 Samsung
8 * ===================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ============LICENSE_END=============================================
22 * ====================================================================
25 package org.onap.music.rest;
27 import java.nio.ByteBuffer;
28 import java.util.List;
30 import java.util.UUID;
32 import javax.ws.rs.Consumes;
33 import javax.ws.rs.DELETE;
34 import javax.ws.rs.GET;
35 import javax.ws.rs.HeaderParam;
36 import javax.ws.rs.POST;
37 import javax.ws.rs.PUT;
38 import javax.ws.rs.Path;
39 import javax.ws.rs.PathParam;
40 import javax.ws.rs.Produces;
41 import javax.ws.rs.core.Context;
42 import javax.ws.rs.core.MediaType;
43 import javax.ws.rs.core.MultivaluedMap;
44 import javax.ws.rs.core.Response;
45 import javax.ws.rs.core.Response.ResponseBuilder;
46 import javax.ws.rs.core.Response.Status;
47 import javax.ws.rs.core.UriInfo;
49 import org.apache.commons.lang3.StringUtils;
50 import org.onap.music.datastore.PreparedQueryObject;
51 import org.onap.music.datastore.jsonobjects.JsonDelete;
52 import org.onap.music.datastore.jsonobjects.JsonInsert;
53 import org.onap.music.datastore.jsonobjects.JsonKeySpace;
54 import org.onap.music.datastore.jsonobjects.JsonTable;
55 import org.onap.music.datastore.jsonobjects.JsonUpdate;
56 import org.onap.music.eelf.logging.EELFLoggerDelegate;
57 import org.onap.music.exceptions.MusicLockingException;
58 import org.onap.music.exceptions.MusicQueryException;
59 import org.onap.music.eelf.logging.format.AppMessages;
60 import org.onap.music.eelf.logging.format.ErrorSeverity;
61 import org.onap.music.eelf.logging.format.ErrorTypes;
62 import org.onap.music.exceptions.MusicServiceException;
63 import org.onap.music.main.MusicCore;
64 import org.onap.music.datastore.Condition;
65 import org.onap.music.datastore.MusicDataStoreHandle;
66 import org.onap.music.main.MusicUtil;
67 import org.onap.music.main.ResultType;
68 import org.onap.music.main.ReturnType;
69 import org.onap.music.response.jsonobjects.JsonResponse;
71 import com.datastax.driver.core.DataType;
72 import com.datastax.driver.core.ResultSet;
73 import com.datastax.driver.core.TableMetadata;
75 import io.swagger.annotations.Api;
76 import io.swagger.annotations.ApiOperation;
77 import io.swagger.annotations.ApiParam;
78 import io.swagger.annotations.ApiResponses;
79 import io.swagger.annotations.ApiResponse;
82 //@Path("/v{version: [0-9]+}/keyspaces")
83 @Path("/v2/keyspaces")
84 @Api(value = "Data Api")
85 public class RestMusicDataAPI {
87 * Header values for Versioning X-minorVersion *** - Used to request or communicate a MINOR
88 * version back from the client to the server, and from the server back to the client - This
89 * will be the MINOR version requested by the client, or the MINOR version of the last MAJOR
90 * version (if not specified by the client on the request) - Contains a single position value
91 * (e.g. if the full version is 1.24.5, X-minorVersion = "24") - Is optional for the client on
92 * request; however, this header should be provided if the client needs to take advantage of
93 * MINOR incremented version functionality - Is mandatory for the server on response
95 *** X-patchVersion *** - Used only to communicate a PATCH version in a response for
96 * troubleshooting purposes only, and will not be provided by the client on request - This will
97 * be the latest PATCH version of the MINOR requested by the client, or the latest PATCH version
98 * of the MAJOR (if not specified by the client on the request) - Contains a single position
99 * value (e.g. if the full version is 1.24.5, X-patchVersion = "5") - Is mandatory for the
100 * server on response (CURRENTLY NOT USED)
102 *** X-latestVersion *** - Used only to communicate an API's latest version - Is mandatory for the
103 * server on response, and shall include the entire version of the API (e.g. if the full version
104 * is 1.24.5, X-latestVersion = "1.24.5") - Used in the response to inform clients that they are
105 * not using the latest version of the API (CURRENTLY NOT USED)
109 private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicDataAPI.class);
110 private static final String XMINORVERSION = "X-minorVersion";
111 private static final String XPATCHVERSION = "X-patchVersion";
112 private static final String NS = "ns";
113 private static final String VERSION = "v2";
115 private class RowIdentifier {
116 public String primarKeyValue;
117 public StringBuilder rowIdString;
118 @SuppressWarnings("unused")
119 public PreparedQueryObject queryObject; // the string with all the row
120 // identifiers separated by AND
122 public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
123 PreparedQueryObject queryObject) {
124 this.primarKeyValue = primaryKeyValue;
125 this.rowIdString = rowIdString;
126 this.queryObject = queryObject;
132 * Create Keyspace REST
135 * @param keyspaceName
141 @ApiOperation(value = "Create Keyspace", response = String.class,hidden = true)
142 @Consumes(MediaType.APPLICATION_JSON)
143 @Produces(MediaType.APPLICATION_JSON)
144 public Response createKeySpace(
145 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
146 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
147 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
148 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
149 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
150 @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns,
151 JsonKeySpace kspObject,
152 @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) {
154 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
155 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) ");
156 logger.info(EELFLoggerDelegate.applicationLogger,"In Create Keyspace " + keyspaceName);
157 if (MusicUtil.isKeyspaceActive() ) {
158 logger.info(EELFLoggerDelegate.applicationLogger,"Creating Keyspace " + keyspaceName);
160 if(kspObject == null || kspObject.getReplicationInfo() == null) {
161 response.status(Status.BAD_REQUEST);
162 return response.entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult()).toMap()).build();
165 String consistency = MusicUtil.EVENTUAL;// for now this needs only eventual consistency
167 PreparedQueryObject queryObject = new PreparedQueryObject();
168 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && kspObject.getConsistencyInfo().get("consistency") != null) {
169 if(MusicUtil.isValidConsistency(kspObject.getConsistencyInfo().get("consistency")))
170 queryObject.setConsistency(kspObject.getConsistencyInfo().get("consistency"));
172 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
174 long start = System.currentTimeMillis();
175 Map<String, Object> replicationInfo = kspObject.getReplicationInfo();
176 String repString = null;
178 repString = "{" + MusicUtil.jsonMaptoSqlString(replicationInfo, ",") + "}";
179 } catch (Exception e) {
180 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGDATA ,ErrorSeverity
181 .CRITICAL, ErrorTypes.DATAERROR, e);
184 queryObject.appendQueryString(
185 "CREATE KEYSPACE " + keyspaceName + " WITH replication = " + repString);
186 if (kspObject.getDurabilityOfWrites() != null) {
187 queryObject.appendQueryString(
188 " AND durable_writes = " + kspObject.getDurabilityOfWrites());
191 queryObject.appendQueryString(";");
192 long end = System.currentTimeMillis();
193 logger.info(EELFLoggerDelegate.applicationLogger,
194 "Time taken for setting up query in create keyspace:" + (end - start));
196 ResultType result = ResultType.FAILURE;
198 result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
199 logger.info(EELFLoggerDelegate.applicationLogger, "result = " + result);
200 } catch ( MusicServiceException ex) {
201 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity
202 .WARN, ErrorTypes.MUSICSERVICEERROR, ex);
203 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("err:" + ex.getMessage()).toMap()).build();
206 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Created").toMap()).build();
208 String vError = "Keyspace Creation has been turned off. Contact DBA to create the keyspace or set keyspace.active to true.";
209 logger.info(EELFLoggerDelegate.applicationLogger,vError);
210 logger.error(EELFLoggerDelegate.errorLogger,vError, AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
211 return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(vError).toMap()).build();
214 EELFLoggerDelegate.mdcRemove("keyspace");
222 * @param keyspaceName
228 @ApiOperation(value = "Delete Keyspace", response = String.class,hidden=true)
229 @Produces(MediaType.APPLICATION_JSON)
230 public Response dropKeySpace(
231 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
232 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
233 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
234 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
235 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
236 @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns,
237 @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) throws Exception {
239 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
240 EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
241 logger.info(EELFLoggerDelegate.applicationLogger,"In Drop Keyspace " + keyspaceName);
242 if (MusicUtil.isKeyspaceActive()) {
243 String consistency = MusicUtil.EVENTUAL;// for now this needs only
244 PreparedQueryObject queryObject = new PreparedQueryObject();
245 queryObject.appendQueryString("DROP KEYSPACE " + keyspaceName + ";");
246 ResultType result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
247 if ( result.equals(ResultType.FAILURE) ) {
248 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Deleteing Keyspace " + keyspaceName).toMap()).build();
250 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Deleted").toMap()).build();
252 String vError = "Keyspace deletion has been turned off. Contact DBA to delete the keyspace or set keyspace.active to true.";
253 logger.info(EELFLoggerDelegate.applicationLogger,vError);
254 logger.error(EELFLoggerDelegate.errorLogger,vError, AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
255 return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(vError).toMap()).build();
258 EELFLoggerDelegate.mdcRemove("keyspace");
270 * @throws Exception -
273 @Path("/{keyspace: .*}/tables/{tablename: .*}")
274 @ApiOperation(value = "Create Table", response = String.class)
275 @Consumes(MediaType.APPLICATION_JSON)
276 @Produces(MediaType.APPLICATION_JSON)
277 @ApiResponses(value={
278 @ApiResponse(code= 400, message = "Will return JSON response with message"),
279 @ApiResponse(code= 401, message = "Unautorized User")
281 public Response createTable(
282 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
283 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
284 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
285 @ApiParam(value = "AID", required = false,hidden = true) @HeaderParam("aid") String aid,
286 @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns,
287 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
289 @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
290 @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename) throws Exception {
292 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
293 if ( null == tableObj ) {
294 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
295 .setError(ResultType.BODYMISSING.getResult()).toMap()).build();
297 if(keyspace == null || keyspace.isEmpty() || tablename == null || tablename.isEmpty()){
298 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
299 .setError("One or more path parameters are not set, please check and try again."
300 + "Parameter values: keyspace='" + keyspace + "' tablename='" + tablename + "'")
303 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
304 String consistency = MusicUtil.EVENTUAL;
305 // for now this needs only eventual consistency
306 String primaryKey = null;
307 String partitionKey = tableObj.getPartitionKey();
308 String clusterKey = tableObj.getClusteringKey();
309 String filteringKey = tableObj.getFilteringKey();
310 if(filteringKey != null) {
311 clusterKey = clusterKey + "," + filteringKey;
313 primaryKey = tableObj.getPrimaryKey(); // get primaryKey if available
315 PreparedQueryObject queryObject = new PreparedQueryObject();
316 // first read the information about the table fields
317 Map<String, String> fields = tableObj.getFields();
318 if (fields == null) {
319 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
320 .setError("Create Table Error: No fields in request").toMap()).build();
323 StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
325 for (Map.Entry<String, String> entry : fields.entrySet()) {
326 if (entry.getKey().equals("PRIMARY KEY")) {
327 primaryKey = entry.getValue(); // replaces primaryKey
328 primaryKey = primaryKey.trim();
330 if (counter == 0 ) fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
331 else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + "");
334 if (counter != (fields.size() - 1) ) {
335 counter = counter + 1;
338 if((primaryKey != null) && (partitionKey == null)) {
339 primaryKey = primaryKey.trim();
340 int count1 = StringUtils.countMatches(primaryKey, ')');
341 int count2 = StringUtils.countMatches(primaryKey, '(');
342 if (count1 != count2) {
343 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
344 .setError("Create Table Error: primary key '(' and ')' do not match, primary key=" + primaryKey)
348 if ( primaryKey.indexOf('(') == -1 || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) == primaryKey.length() ) ) {
349 if (primaryKey.contains(",") ) {
350 partitionKey= primaryKey.substring(0,primaryKey.indexOf(','));
351 partitionKey=partitionKey.replaceAll("[\\(]+","");
352 clusterKey=primaryKey.substring(primaryKey.indexOf(',')+1); // make sure index
353 clusterKey=clusterKey.replaceAll("[)]+", "");
355 partitionKey=primaryKey;
356 partitionKey=partitionKey.replaceAll("[\\)]+","");
357 partitionKey=partitionKey.replaceAll("[\\(]+","");
360 } else { // not null and has ) before the last char
361 partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
362 partitionKey=partitionKey.replaceAll("[\\(]+","");
363 partitionKey = partitionKey.trim();
364 clusterKey= primaryKey.substring(primaryKey.indexOf(')'));
365 clusterKey=clusterKey.replaceAll("[\\(]+","");
366 clusterKey=clusterKey.replaceAll("[\\)]+","");
367 clusterKey = clusterKey.trim();
368 if (clusterKey.indexOf(',') == 0) {
369 clusterKey=clusterKey.substring(1);
371 clusterKey = clusterKey.trim();
372 if (clusterKey.equals(",") ) clusterKey=""; // print error if needed ( ... ),)
375 if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
376 && (partitionKey.equalsIgnoreCase(clusterKey) ||
377 clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
378 logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey + " and primary key=" + primaryKey );
379 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
380 "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ") of"
381 + " primary key=" + primaryKey)
386 if (partitionKey.isEmpty() ) primaryKey="";
387 else if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey + ")";
388 else primaryKey=" (" + partitionKey + ")," + clusterKey;
391 if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
393 } else { // end of length > 0
395 if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
396 && (partitionKey.equalsIgnoreCase(clusterKey) ||
397 clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
398 logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey);
399 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
400 "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")")
404 if (partitionKey.isEmpty() ) primaryKey="";
405 else if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey + ")";
406 else primaryKey=" (" + partitionKey + ")," + clusterKey;
408 if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
410 fieldsString.append(")");
412 } // end of last field check
415 // information about the name-value style properties
416 Map<String, Object> propertiesMap = tableObj.getProperties();
417 StringBuilder propertiesString = new StringBuilder();
418 if (propertiesMap != null) {
420 for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
421 Object ot = entry.getValue();
422 String value = ot + "";
423 if (ot instanceof String) {
424 value = "'" + value + "'";
425 } else if (ot instanceof Map) {
426 @SuppressWarnings("unchecked")
427 Map<String, Object> otMap = (Map<String, Object>) ot;
428 value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
431 propertiesString.append(entry.getKey() + "=" + value + "");
432 if (counter != propertiesMap.size() - 1)
433 propertiesString.append(" AND ");
435 counter = counter + 1;
439 String clusteringOrder = tableObj.getClusteringOrder();
441 if (clusteringOrder != null && !(clusteringOrder.isEmpty())) {
442 String[] arrayClusterOrder = clusteringOrder.split("[,]+");
444 for (int i = 0; i < arrayClusterOrder.length; i++) {
445 String[] clusterS = arrayClusterOrder[i].trim().split("[ ]+");
446 if ( (clusterS.length ==2) && (clusterS[1].equalsIgnoreCase("ASC") || clusterS[1].equalsIgnoreCase("DESC"))) {
449 return response.status(Status.BAD_REQUEST)
450 .entity(new JsonResponse(ResultType.FAILURE)
451 .setError("createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname order; please correct clusteringOrder:"+ clusteringOrder+".")
454 // add validation for column names in cluster key
457 if (!(clusterKey.isEmpty())) {
458 clusteringOrder = "CLUSTERING ORDER BY (" +clusteringOrder +")";
459 //cjc check if propertiesString.length() >0 instead propertiesMap
460 if (propertiesMap != null) {
461 propertiesString.append(" AND "+ clusteringOrder);
463 propertiesString.append(clusteringOrder);
466 logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty ");
470 queryObject.appendQueryString(
471 "CREATE TABLE " + keyspace + "." + tablename + " " + fieldsString);
474 if (propertiesString != null && propertiesString.length()>0 )
475 queryObject.appendQueryString(" WITH " + propertiesString);
476 queryObject.appendQueryString(";");
477 ResultType result = ResultType.FAILURE;
479 result = MusicCore.createTable(keyspace, tablename, queryObject, consistency);
480 } catch (MusicServiceException ex) {
481 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.MUSICSERVICEERROR);
482 response.status(Status.BAD_REQUEST);
483 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
485 if ( result.equals(ResultType.FAILURE) ) {
486 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Creating Table " + tablename).toMap()).build();
488 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("TableName " + tablename.trim() + " Created under keyspace " + keyspace.trim()).toMap()).build();
490 EELFLoggerDelegate.mdcRemove("keyspace");
503 @Path("/{keyspace: .*}/tables/{tablename: .*}/index/{field: .*}")
504 @ApiOperation(value = "Create Index", response = String.class)
505 @Produces(MediaType.APPLICATION_JSON)
506 public Response createIndex(
507 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
508 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
509 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
510 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
511 @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
512 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
513 @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
514 @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename,
515 @ApiParam(value = "Field Name",required = true) @PathParam("field") String fieldName,
516 @Context UriInfo info) throws Exception {
518 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
519 if ((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty()) || (fieldName == null || fieldName.isEmpty())){
520 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
521 .setError("one or more path parameters are not set, please check and try again")
524 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
525 MultivaluedMap<String, String> rowParams = info.getQueryParameters();
526 String indexName = "";
527 if (rowParams.getFirst("index_name") != null)
528 indexName = rowParams.getFirst("index_name");
529 PreparedQueryObject query = new PreparedQueryObject();
530 query.appendQueryString("Create index if not exists " + indexName + " on " + keyspace + "."
531 + tablename + " (" + fieldName + ");");
533 ResultType result = ResultType.FAILURE;
535 result = MusicCore.nonKeyRelatedPut(query, "eventual");
536 } catch (MusicServiceException ex) {
537 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity
538 .CRITICAL, ErrorTypes.GENERALSERVICEERROR, ex);
539 response.status(Status.BAD_REQUEST);
540 return response.entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
542 if ( result.equals(ResultType.SUCCESS) ) {
543 return response.status(Status.OK).entity(new JsonResponse(result).setMessage("Index Created on " + keyspace+"."+tablename+"."+fieldName).toMap()).build();
545 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Unknown Error in create index.").toMap()).build();
548 EELFLoggerDelegate.mdcRemove("keyspace");
561 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
562 @ApiOperation(value = "Insert Into Table", response = String.class)
563 @Consumes(MediaType.APPLICATION_JSON)
564 @Produces(MediaType.APPLICATION_JSON)
565 public Response insertIntoTable(
566 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
567 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
568 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
569 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
570 @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns,
571 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
573 @ApiParam(value = "Keyspace Name",
574 required = true) @PathParam("keyspace") String keyspace,
575 @ApiParam(value = "Table Name",
576 required = true) @PathParam("tablename") String tablename) {
578 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
579 if ( null == insObj ) {
580 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
581 .setError(ResultType.BODYMISSING.getResult()).toMap()).build();
583 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
584 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
585 .setError("one or more path parameters are not set, please check and try again")
588 EELFLoggerDelegate.mdcPut("keyspace","(" + keyspace + ")");
589 PreparedQueryObject queryObject = new PreparedQueryObject();
590 TableMetadata tableInfo = null;
592 tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
593 if(tableInfo == null) {
594 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Table name doesn't exists. Please check the table name.").toMap()).build();
596 } catch (MusicServiceException e) {
597 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
598 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
600 String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
601 StringBuilder fieldsString = new StringBuilder("(vector_ts,");
603 String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
604 StringBuilder valueString = new StringBuilder("(" + "?" + ",");
605 queryObject.addValue(vectorTs);
607 Map<String, Object> valuesMap = insObj.getValues();
608 if (valuesMap==null) {
609 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
610 .setError("Nothing to insert. No values provided in request.").toMap()).build();
613 String primaryKey = "";
614 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
615 fieldsString.append("" + entry.getKey());
616 Object valueObj = entry.getValue();
617 if (primaryKeyName.equals(entry.getKey())) {
618 primaryKey = entry.getValue() + "";
619 primaryKey = primaryKey.replace("'", "''");
621 DataType colType = null;
623 colType = tableInfo.getColumn(entry.getKey()).getType();
624 } catch(NullPointerException ex) {
625 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey
626 (), AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex);
627 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
630 Object formattedValue = null;
632 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
633 } catch (Exception e) {
634 logger.error(EELFLoggerDelegate.errorLogger,e);
636 valueString.append("?");
638 queryObject.addValue(formattedValue);
640 if (counter == valuesMap.size() - 1) {
641 fieldsString.append(")");
642 valueString.append(")");
644 fieldsString.append(",");
645 valueString.append(",");
647 counter = counter + 1;
651 Map<String, byte[]> objectMap = insObj.getObjectMap();
652 if(objectMap != null) {
653 for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
655 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
656 valueString.replace(valueString.length()-1, valueString.length(), ",");
658 fieldsString.append("" + entry.getKey());
659 byte[] valueObj = entry.getValue();
660 if (primaryKeyName.equals(entry.getKey())) {
661 primaryKey = entry.getValue() + "";
662 primaryKey = primaryKey.replace("'", "''");
664 DataType colType = tableInfo.getColumn(entry.getKey()).getType();
665 ByteBuffer formattedValue = null;
666 if(colType.toString().toLowerCase().contains("blob")) {
667 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
669 valueString.append("?");
670 queryObject.addValue(formattedValue);
671 counter = counter + 1;
672 fieldsString.append(",");
673 valueString.append(",");
677 if(primaryKey == null || primaryKey.length() <= 0) {
678 logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
679 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Some required partition key parts are missing: "+primaryKeyName).toMap()).build();
682 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
683 valueString.replace(valueString.length()-1, valueString.length(), ")");
685 queryObject.appendQueryString("INSERT INTO " + keyspace + "." + tablename + " "
686 + fieldsString + " VALUES " + valueString);
688 String ttl = insObj.getTtl();
689 String timestamp = insObj.getTimestamp();
691 if ((ttl != null) && (timestamp != null)) {
692 logger.info(EELFLoggerDelegate.applicationLogger, "both there");
693 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
694 queryObject.addValue(Integer.parseInt(ttl));
695 queryObject.addValue(Long.parseLong(timestamp));
698 if ((ttl != null) && (timestamp == null)) {
699 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
700 queryObject.appendQueryString(" USING TTL ?");
701 queryObject.addValue(Integer.parseInt(ttl));
704 if ((ttl == null) && (timestamp != null)) {
705 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
706 queryObject.appendQueryString(" USING TIMESTAMP ?");
707 queryObject.addValue(Long.parseLong(timestamp));
710 queryObject.appendQueryString(";");
712 ReturnType result = null;
713 String consistency = insObj.getConsistencyInfo().get("type");
714 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && insObj.getConsistencyInfo().get("consistency") != null) {
715 if(MusicUtil.isValidConsistency(insObj.getConsistencyInfo().get("consistency"))) {
716 queryObject.setConsistency(insObj.getConsistencyInfo().get("consistency"));
718 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
721 queryObject.setOperation("insert");
723 if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
724 result = MusicCore.eventualPut(queryObject);
725 } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
726 String lockId = insObj.getConsistencyInfo().get("lockId");
728 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
729 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
730 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
731 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
733 result = MusicCore.criticalPut(keyspace, tablename, primaryKey, queryObject, lockId,null);
734 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
735 result = MusicCore.atomicPut(keyspace, tablename, primaryKey, queryObject, null);
737 } catch (Exception ex) {
738 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity
739 .WARN, ErrorTypes.MUSICSERVICEERROR, ex);
740 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
743 logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
744 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
745 }else if(result.getResult() == ResultType.FAILURE) {
746 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result.getResult()).setError(result.getMessage()).toMap()).build();
748 return response.status(Status.OK).entity(new JsonResponse(result.getResult()).setMessage("Insert Successful").toMap()).build();
750 EELFLoggerDelegate.mdcRemove("keyspace");
761 * @throws MusicServiceException
762 * @throws MusicQueryException
766 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
767 @ApiOperation(value = "Update Table", response = String.class)
768 @Consumes(MediaType.APPLICATION_JSON)
769 @Produces(MediaType.APPLICATION_JSON)
770 public Response updateTable(
771 @ApiParam(value = "Major Version",
772 required = true) @PathParam("version") String version,
773 @ApiParam(value = "Minor Version",
774 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
775 @ApiParam(value = "Patch Version",
776 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
777 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
778 @ApiParam(value = "Application namespace",
779 required = false, hidden = true) @HeaderParam(NS) String ns,
780 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
781 JsonUpdate updateObj,
782 @ApiParam(value = "Keyspace Name",
783 required = true) @PathParam("keyspace") String keyspace,
784 @ApiParam(value = "Table Name",
785 required = true) @PathParam("tablename") String tablename,
786 @Context UriInfo info) throws MusicQueryException, MusicServiceException {
788 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
789 if ( null == updateObj ) {
790 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
791 .setError(ResultType.BODYMISSING.getResult()).toMap()).build();
793 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
794 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
795 .setError("one or more path parameters are not set, please check and try again")
798 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
799 long startTime = System.currentTimeMillis();
800 String operationId = UUID.randomUUID().toString(); // just for infoging
802 String consistency = updateObj.getConsistencyInfo().get("type");
804 logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
805 + " update-" + operationId + "-------------------------");
806 // obtain the field value pairs of the update
808 PreparedQueryObject queryObject = new PreparedQueryObject();
809 Map<String, Object> valuesMap = updateObj.getValues();
811 TableMetadata tableInfo;
813 tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
814 } catch (MusicServiceException e) {
815 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
816 .GENERALSERVICEERROR, e);
817 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
819 if (tableInfo == null) {
820 logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+tablename, AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
821 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
822 .setError("Table information not found. Please check input for table name= "
823 + keyspace + "." + tablename).toMap()).build();
825 String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
826 StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
827 queryObject.addValue(vectorTs);
829 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
830 Object valueObj = entry.getValue();
831 DataType colType = null;
833 colType = tableInfo.getColumn(entry.getKey()).getType();
834 } catch(NullPointerException ex) {
835 logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey(), ex);
836 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
838 Object valueString = null;
840 valueString = MusicUtil.convertToActualDataType(colType, valueObj);
841 } catch (Exception e) {
842 logger.error(EELFLoggerDelegate.errorLogger,e);
844 fieldValueString.append(entry.getKey() + "= ?");
845 queryObject.addValue(valueString);
846 if (counter != valuesMap.size() - 1) {
847 fieldValueString.append(",");
849 counter = counter + 1;
851 String ttl = updateObj.getTtl();
852 String timestamp = updateObj.getTimestamp();
854 queryObject.appendQueryString("UPDATE " + keyspace + "." + tablename + " ");
855 if ((ttl != null) && (timestamp != null)) {
856 logger.info("both there");
857 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
858 queryObject.addValue(Integer.parseInt(ttl));
859 queryObject.addValue(Long.parseLong(timestamp));
862 if ((ttl != null) && (timestamp == null)) {
863 logger.info("ONLY TTL there");
864 queryObject.appendQueryString(" USING TTL ?");
865 queryObject.addValue(Integer.parseInt(ttl));
868 if ((ttl == null) && (timestamp != null)) {
869 logger.info("ONLY timestamp there");
870 queryObject.appendQueryString(" USING TIMESTAMP ?");
871 queryObject.addValue(Long.parseLong(timestamp));
873 // get the row specifier
874 RowIdentifier rowId = null;
876 rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
877 if(rowId == null || rowId.primarKeyValue.isEmpty()) {
878 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
879 .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();
881 } catch (MusicServiceException ex) {
882 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
883 .GENERALSERVICEERROR, ex);
884 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
887 queryObject.appendQueryString(
888 " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
890 // get the conditional, if any
891 Condition conditionInfo;
892 if (updateObj.getConditions() == null) {
893 conditionInfo = null;
895 // to avoid parsing repeatedly, just send the select query to obtain row
896 PreparedQueryObject selectQuery = new PreparedQueryObject();
897 selectQuery.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + " WHERE "
898 + rowId.rowIdString + ";");
899 selectQuery.addValue(rowId.primarKeyValue);
900 conditionInfo = new Condition(updateObj.getConditions(), selectQuery);
903 ReturnType operationResult = null;
904 long jsonParseCompletionTime = System.currentTimeMillis();
906 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && updateObj.getConsistencyInfo().get("consistency") != null) {
907 if(MusicUtil.isValidConsistency(updateObj.getConsistencyInfo().get("consistency"))) {
908 queryObject.setConsistency(updateObj.getConsistencyInfo().get("consistency"));
910 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
913 queryObject.setOperation("update");
914 if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
915 operationResult = MusicCore.eventualPut(queryObject);
916 } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
917 String lockId = updateObj.getConsistencyInfo().get("lockId");
919 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
920 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
921 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
922 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
924 operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
925 queryObject, lockId, conditionInfo);
926 } else if (consistency.equalsIgnoreCase("atomic_delete_lock")) {
927 // this function is mainly for the benchmarks
929 operationResult = MusicCore.atomicPutWithDeleteLock(keyspace, tablename,
930 rowId.primarKeyValue, queryObject, conditionInfo);
931 } catch (MusicLockingException e) {
932 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN,
933 ErrorTypes.GENERALSERVICEERROR, e);
934 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
936 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
938 operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
939 queryObject, conditionInfo);
940 } catch (MusicLockingException e) {
941 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, e);
942 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
944 } else if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
945 operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
947 long actualUpdateCompletionTime = System.currentTimeMillis();
949 long endTime = System.currentTimeMillis();
950 String timingString = "Time taken in ms for Music " + consistency + " update-" + operationId
951 + ":" + "|total operation time:" + (endTime - startTime)
952 + "|json parsing time:" + (jsonParseCompletionTime - startTime)
953 + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
956 if (operationResult != null && operationResult.getTimingInfo() != null) {
957 String lockManagementTime = operationResult.getTimingInfo();
958 timingString = timingString + lockManagementTime;
960 logger.info(EELFLoggerDelegate.applicationLogger, timingString);
962 if (operationResult==null) {
963 logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
964 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
966 if ( operationResult.getResult() == ResultType.SUCCESS ) {
967 return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
969 logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
970 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(operationResult.getResult()).setError(operationResult.getMessage()).toMap()).build();
973 EELFLoggerDelegate.mdcRemove("keyspace");
984 * @throws MusicServiceException
985 * @throws MusicQueryException
989 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
990 @ApiOperation(value = "Delete From table", response = String.class)
991 @Consumes(MediaType.APPLICATION_JSON)
992 @Produces(MediaType.APPLICATION_JSON)
993 public Response deleteFromTable(
994 @ApiParam(value = "Major Version",
995 required = true) @PathParam("version") String version,
996 @ApiParam(value = "Minor Version",
997 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
998 @ApiParam(value = "Patch Version",
999 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1000 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
1001 @ApiParam(value = "Application namespace",
1002 required = false, hidden = true) @HeaderParam(NS) String ns,
1003 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1005 @ApiParam(value = "Keyspace Name",
1006 required = true) @PathParam("keyspace") String keyspace,
1007 @ApiParam(value = "Table Name",
1008 required = true) @PathParam("tablename") String tablename,
1009 @Context UriInfo info) throws MusicQueryException, MusicServiceException {
1011 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1012 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1013 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1014 .setError("one or more path parameters are not set, please check and try again")
1017 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1018 if(delObj == null) {
1019 logger.error(EELFLoggerDelegate.errorLogger,ResultType.BODYMISSING.getResult(), AppMessages.MISSINGDATA ,ErrorSeverity.WARN, ErrorTypes.DATAERROR);
1020 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult()).toMap()).build();
1022 PreparedQueryObject queryObject = new PreparedQueryObject();
1023 StringBuilder columnString = new StringBuilder();
1026 List<String> columnList = delObj.getColumns();
1027 if (columnList != null) {
1028 for (String column : columnList) {
1029 columnString.append(column);
1030 if (counter != columnList.size() - 1)
1031 columnString.append(",");
1032 counter = counter + 1;
1036 // get the row specifier
1037 RowIdentifier rowId = null;
1039 rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1040 } catch (MusicServiceException ex) {
1041 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
1042 .GENERALSERVICEERROR, ex);
1043 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1045 String rowSpec = rowId.rowIdString.toString();
1047 if ((columnList != null) && (!rowSpec.isEmpty())) {
1048 queryObject.appendQueryString("DELETE " + columnString + " FROM " + keyspace + "."
1049 + tablename + " WHERE " + rowSpec + ";");
1052 if ((columnList == null) && (!rowSpec.isEmpty())) {
1053 queryObject.appendQueryString("DELETE FROM " + keyspace + "." + tablename + " WHERE "
1057 if ((columnList != null) && (rowSpec.isEmpty())) {
1058 queryObject.appendQueryString(
1059 "DELETE " + columnString + " FROM " + keyspace + "." + rowSpec + ";");
1061 // get the conditional, if any
1062 Condition conditionInfo;
1063 if (delObj.getConditions() == null) {
1064 conditionInfo = null;
1066 // to avoid parsing repeatedly, just send the select query to
1068 PreparedQueryObject selectQuery = new PreparedQueryObject();
1069 selectQuery.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + " WHERE "
1070 + rowId.rowIdString + ";");
1071 selectQuery.addValue(rowId.primarKeyValue);
1072 conditionInfo = new Condition(delObj.getConditions(), selectQuery);
1075 String consistency = delObj.getConsistencyInfo().get("type");
1078 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && delObj.getConsistencyInfo().get("consistency")!=null) {
1079 if(MusicUtil.isValidConsistency(delObj.getConsistencyInfo().get("consistency"))) {
1080 queryObject.setConsistency(delObj.getConsistencyInfo().get("consistency"));
1082 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR)
1083 .setError("Invalid Consistency type").toMap()).build();
1086 ReturnType operationResult = null;
1087 queryObject.setOperation("delete");
1089 if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
1090 operationResult = MusicCore.eventualPut(queryObject);
1091 else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1092 String lockId = delObj.getConsistencyInfo().get("lockId");
1093 if(lockId == null) {
1094 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1095 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1096 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1097 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1099 operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
1100 queryObject, lockId, conditionInfo);
1101 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1102 operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
1103 queryObject, conditionInfo);
1104 } else if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
1105 operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
1107 } catch (MusicLockingException e) {
1108 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, e);
1109 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1110 .setError("Unable to perform Delete operation. Exception from music").toMap()).build();
1112 if (operationResult==null) {
1113 logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1114 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
1116 if (operationResult.getResult().equals(ResultType.SUCCESS)) {
1117 return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
1119 logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1120 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(operationResult.getMessage()).toMap()).build();
1123 EELFLoggerDelegate.mdcRemove("keyspace");
1135 @Path("/{keyspace: .*}/tables/{tablename: .*}")
1136 @ApiOperation(value = "Drop Table", response = String.class)
1137 @Produces(MediaType.APPLICATION_JSON)
1138 public Response dropTable(
1139 @ApiParam(value = "Major Version",
1140 required = true) @PathParam("version") String version,
1141 @ApiParam(value = "Minor Version",
1142 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1143 @ApiParam(value = "Patch Version",
1144 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1145 @ApiParam(value = "AID", required = false,hidden = true) @HeaderParam("aid") String aid,
1146 @ApiParam(value = "Application namespace",
1147 required = false, hidden = true) @HeaderParam(NS) String ns,
1148 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1149 @ApiParam(value = "Keyspace Name",
1150 required = true) @PathParam("keyspace") String keyspace,
1151 @ApiParam(value = "Table Name",
1152 required = true) @PathParam("tablename") String tablename) throws Exception {
1154 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1155 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1156 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1157 .setError("one or more path parameters are not set, please check and try again")
1160 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1161 String consistency = "eventual";// for now this needs only eventual consistency
1162 PreparedQueryObject query = new PreparedQueryObject();
1163 query.appendQueryString("DROP TABLE " + keyspace + "." + tablename + ";");
1165 return response.status(Status.OK).entity(new JsonResponse(MusicCore.nonKeyRelatedPut(query, consistency)).toMap()).build();
1166 } catch (MusicServiceException ex) {
1167 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes
1168 .GENERALSERVICEERROR);
1169 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1172 EELFLoggerDelegate.mdcRemove("keyspace");
1185 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows/criticalget")
1186 @ApiOperation(value = "Select Critical", response = Map.class)
1187 @Consumes(MediaType.APPLICATION_JSON)
1188 @Produces(MediaType.APPLICATION_JSON)
1189 public Response selectCritical(
1190 @ApiParam(value = "Major Version",
1191 required = true) @PathParam("version") String version,
1192 @ApiParam(value = "Minor Version",
1193 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1194 @ApiParam(value = "Patch Version",
1195 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1196 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
1197 @ApiParam(value = "Application namespace",
1198 required = false, hidden = true) @HeaderParam(NS) String ns,
1199 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1201 @ApiParam(value = "Keyspace Name",
1202 required = true) @PathParam("keyspace") String keyspace,
1203 @ApiParam(value = "Table Name",
1204 required = true) @PathParam("tablename") String tablename,
1205 @Context UriInfo info) throws Exception {
1207 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1208 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1209 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1210 .setError("one or more path parameters are not set, please check and try again")
1213 if(selObj == null) {
1214 logger.error(EELFLoggerDelegate.errorLogger,ResultType.BODYMISSING.getResult(), AppMessages.MISSINGDATA ,ErrorSeverity.WARN, ErrorTypes.DATAERROR);
1215 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult()).toMap()).build();
1218 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1219 String lockId = selObj.getConsistencyInfo().get("lockId");
1220 PreparedQueryObject queryObject = new PreparedQueryObject();
1221 RowIdentifier rowId = null;
1223 rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1224 } catch (MusicServiceException ex) {
1225 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
1226 .GENERALSERVICEERROR, ex);
1227 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1229 queryObject.appendQueryString(
1230 "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowId.rowIdString + ";");
1232 ResultSet results = null;
1234 String consistency = selObj.getConsistencyInfo().get("type");
1236 if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1237 if(lockId == null) {
1238 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1239 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1240 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1241 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1243 results = MusicCore.criticalGet(keyspace, tablename, rowId.primarKeyValue, queryObject,lockId);
1244 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1245 results = MusicCore.atomicGet(keyspace, tablename, rowId.primarKeyValue, queryObject);
1247 }catch(Exception ex) {
1248 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1251 if(results!=null && results.getAvailableWithoutFetching() >0) {
1252 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1254 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setError("No data found").toMap()).build();
1256 EELFLoggerDelegate.mdcRemove("keyspace");
1269 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
1270 @ApiOperation(value = "Select All or Select Specific", response = Map.class)
1271 @Produces(MediaType.APPLICATION_JSON)
1272 public Response select(
1273 @ApiParam(value = "Major Version",
1274 required = true) @PathParam("version") String version,
1275 @ApiParam(value = "Minor Version",
1276 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1277 @ApiParam(value = "Patch Version",
1278 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1279 @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
1280 @ApiParam(value = "Application namespace",
1281 required = false,hidden = true) @HeaderParam(NS) String ns,
1282 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1283 @ApiParam(value = "Keyspace Name",
1284 required = true) @PathParam("keyspace") String keyspace,
1285 @ApiParam(value = "Table Name",
1286 required = true) @PathParam("tablename") String tablename,
1287 @Context UriInfo info) throws Exception {
1289 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1290 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1291 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1292 .setError("one or more path parameters are not set, please check and try again")
1295 EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspace + " ) ");
1296 PreparedQueryObject queryObject = new PreparedQueryObject();
1298 if (info.getQueryParameters().isEmpty()) { // select all
1299 queryObject.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + ";");
1301 int limit = -1; // do not limit the number of results
1303 queryObject = selectSpecificQuery(keyspace, tablename, info, limit);
1304 } catch (MusicServiceException ex) {
1305 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN,
1306 ErrorTypes.GENERALSERVICEERROR, ex);
1307 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1311 ResultSet results = MusicCore.get(queryObject);
1312 if(results.getAvailableWithoutFetching() >0) {
1313 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1315 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).setError("No data found").toMap()).build();
1316 } catch (MusicServiceException ex) {
1317 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.ERROR,
1318 ErrorTypes.MUSICSERVICEERROR, ex);
1319 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1322 EELFLoggerDelegate.mdcRemove("keyspace");
1333 * @throws MusicServiceException
1335 public PreparedQueryObject selectSpecificQuery(String keyspace,
1336 String tablename, UriInfo info, int limit)
1337 throws MusicServiceException {
1338 PreparedQueryObject queryObject = new PreparedQueryObject();
1339 StringBuilder rowIdString = getRowIdentifier(keyspace,
1340 tablename,info.getQueryParameters(),queryObject).rowIdString;
1341 queryObject.appendQueryString(
1342 "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowIdString);
1344 queryObject.appendQueryString(" LIMIT " + limit);
1346 queryObject.appendQueryString(";");
1355 * @param queryObject
1357 * @throws MusicServiceException
1359 private RowIdentifier getRowIdentifier(String keyspace, String tablename,
1360 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
1361 throws MusicServiceException {
1362 StringBuilder rowSpec = new StringBuilder();
1364 TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
1365 if (tableInfo == null) {
1366 logger.error(EELFLoggerDelegate.errorLogger,
1367 "Table information not found. Please check input for table name= "
1368 + keyspace + "." + tablename);
1369 throw new MusicServiceException(
1370 "Table information not found. Please check input for table name= "
1371 + keyspace + "." + tablename);
1373 StringBuilder primaryKey = new StringBuilder();
1374 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
1375 String keyName = entry.getKey();
1376 List<String> valueList = entry.getValue();
1377 String indValue = valueList.get(0);
1378 DataType colType = null;
1379 Object formattedValue = null;
1381 colType = tableInfo.getColumn(entry.getKey()).getType();
1382 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
1383 } catch (Exception e) {
1384 logger.error(EELFLoggerDelegate.errorLogger,e);
1386 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
1387 primaryKey.append(indValue);
1389 rowSpec.append(keyName + "= ?");
1390 queryObject.addValue(formattedValue);
1391 if (counter != rowParams.size() - 1) {
1392 rowSpec.append(" AND ");
1394 counter = counter + 1;
1396 return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);