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) @HeaderParam("aid") String aid,
149 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
150 @ApiParam(value = "Application namespace",required = 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) @HeaderParam("aid") String aid,
235 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
236 @ApiParam(value = "Application namespace",required = 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) @HeaderParam("aid") String aid,
286 @ApiParam(value = "Application namespace",required = 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(keyspace == null || keyspace.isEmpty() || tablename == null || tablename.isEmpty()){
294 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
295 .setError("One or more path parameters are not set, please check and try again."
296 + "Parameter values: keyspace='" + keyspace + "' tablename='" + tablename + "'")
299 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
300 String consistency = MusicUtil.EVENTUAL;
301 // for now this needs only eventual consistency
302 String primaryKey = null;
303 String partitionKey = tableObj.getPartitionKey();
304 String clusterKey = tableObj.getClusteringKey();
305 String filteringKey = tableObj.getFilteringKey();
306 if(filteringKey != null) {
307 clusterKey = clusterKey + "," + filteringKey;
309 primaryKey = tableObj.getPrimaryKey(); // get primaryKey if available
311 PreparedQueryObject queryObject = new PreparedQueryObject();
312 // first read the information about the table fields
313 Map<String, String> fields = tableObj.getFields();
314 if (fields == null) {
315 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
316 .setError("Create Table Error: No fields in request").toMap()).build();
319 StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
321 for (Map.Entry<String, String> entry : fields.entrySet()) {
322 if (entry.getKey().equals("PRIMARY KEY")) {
323 primaryKey = entry.getValue(); // replaces primaryKey
324 primaryKey = primaryKey.trim();
326 if (counter == 0 ) fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
327 else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + "");
330 if (counter != (fields.size() - 1) ) {
331 counter = counter + 1;
334 if((primaryKey != null) && (partitionKey == null)) {
335 primaryKey = primaryKey.trim();
336 int count1 = StringUtils.countMatches(primaryKey, ')');
337 int count2 = StringUtils.countMatches(primaryKey, '(');
338 if (count1 != count2) {
339 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
340 .setError("Create Table Error: primary key '(' and ')' do not match, primary key=" + primaryKey)
344 if ( primaryKey.indexOf('(') == -1 || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) == primaryKey.length() ) ) {
345 if (primaryKey.contains(",") ) {
346 partitionKey= primaryKey.substring(0,primaryKey.indexOf(','));
347 partitionKey=partitionKey.replaceAll("[\\(]+","");
348 clusterKey=primaryKey.substring(primaryKey.indexOf(',')+1); // make sure index
349 clusterKey=clusterKey.replaceAll("[)]+", "");
351 partitionKey=primaryKey;
352 partitionKey=partitionKey.replaceAll("[\\)]+","");
353 partitionKey=partitionKey.replaceAll("[\\(]+","");
356 } else { // not null and has ) before the last char
357 partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
358 partitionKey=partitionKey.replaceAll("[\\(]+","");
359 partitionKey = partitionKey.trim();
360 clusterKey= primaryKey.substring(primaryKey.indexOf(')'));
361 clusterKey=clusterKey.replaceAll("[\\(]+","");
362 clusterKey=clusterKey.replaceAll("[\\)]+","");
363 clusterKey = clusterKey.trim();
364 if (clusterKey.indexOf(',') == 0) {
365 clusterKey=clusterKey.substring(1);
367 clusterKey = clusterKey.trim();
368 if (clusterKey.equals(",") ) clusterKey=""; // print error if needed ( ... ),)
371 if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
372 && (partitionKey.equalsIgnoreCase(clusterKey) ||
373 clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
374 logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey + " and primary key=" + primaryKey );
375 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
376 "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ") of"
377 + " primary key=" + primaryKey)
382 if (partitionKey.isEmpty() ) primaryKey="";
383 else if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey + ")";
384 else primaryKey=" (" + partitionKey + ")," + clusterKey;
387 if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
389 } else { // end of length > 0
391 if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
392 && (partitionKey.equalsIgnoreCase(clusterKey) ||
393 clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
394 logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey);
395 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
396 "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")")
400 if (partitionKey.isEmpty() ) primaryKey="";
401 else if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey + ")";
402 else primaryKey=" (" + partitionKey + ")," + clusterKey;
404 if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
406 fieldsString.append(")");
408 } // end of last field check
411 // information about the name-value style properties
412 Map<String, Object> propertiesMap = tableObj.getProperties();
413 StringBuilder propertiesString = new StringBuilder();
414 if (propertiesMap != null) {
416 for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
417 Object ot = entry.getValue();
418 String value = ot + "";
419 if (ot instanceof String) {
420 value = "'" + value + "'";
421 } else if (ot instanceof Map) {
422 @SuppressWarnings("unchecked")
423 Map<String, Object> otMap = (Map<String, Object>) ot;
424 value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
427 propertiesString.append(entry.getKey() + "=" + value + "");
428 if (counter != propertiesMap.size() - 1)
429 propertiesString.append(" AND ");
431 counter = counter + 1;
435 String clusteringOrder = tableObj.getClusteringOrder();
437 if (clusteringOrder != null && !(clusteringOrder.isEmpty())) {
438 String[] arrayClusterOrder = clusteringOrder.split("[,]+");
440 for (int i = 0; i < arrayClusterOrder.length; i++) {
441 String[] clusterS = arrayClusterOrder[i].trim().split("[ ]+");
442 if ( (clusterS.length ==2) && (clusterS[1].equalsIgnoreCase("ASC") || clusterS[1].equalsIgnoreCase("DESC"))) {
445 return response.status(Status.BAD_REQUEST)
446 .entity(new JsonResponse(ResultType.FAILURE)
447 .setError("createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname order; please correct clusteringOrder:"+ clusteringOrder+".")
450 // add validation for column names in cluster key
453 if (!(clusterKey.isEmpty())) {
454 clusteringOrder = "CLUSTERING ORDER BY (" +clusteringOrder +")";
455 //cjc check if propertiesString.length() >0 instead propertiesMap
456 if (propertiesMap != null) {
457 propertiesString.append(" AND "+ clusteringOrder);
459 propertiesString.append(clusteringOrder);
462 logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty ");
466 queryObject.appendQueryString(
467 "CREATE TABLE " + keyspace + "." + tablename + " " + fieldsString);
470 if (propertiesString != null && propertiesString.length()>0 )
471 queryObject.appendQueryString(" WITH " + propertiesString);
472 queryObject.appendQueryString(";");
473 ResultType result = ResultType.FAILURE;
475 result = MusicCore.createTable(keyspace, tablename, queryObject, consistency);
476 } catch (MusicServiceException ex) {
477 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.MUSICSERVICEERROR);
478 response.status(Status.BAD_REQUEST);
479 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
481 if ( result.equals(ResultType.FAILURE) ) {
482 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Creating Table " + tablename).toMap()).build();
484 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("TableName " + tablename.trim() + " Created under keyspace " + keyspace.trim()).toMap()).build();
486 EELFLoggerDelegate.mdcRemove("keyspace");
499 @Path("/{keyspace: .*}/tables/{tablename: .*}/index/{field: .*}")
500 @ApiOperation(value = "Create Index", response = String.class)
501 @Produces(MediaType.APPLICATION_JSON)
502 public Response createIndex(
503 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
504 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
505 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
506 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
507 @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
508 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
509 @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
510 @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename,
511 @ApiParam(value = "Field Name",required = true) @PathParam("field") String fieldName,
512 @Context UriInfo info) throws Exception {
514 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
515 if ((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty()) || (fieldName == null || fieldName.isEmpty())){
516 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
517 .setError("one or more path parameters are not set, please check and try again")
520 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
521 MultivaluedMap<String, String> rowParams = info.getQueryParameters();
522 String indexName = "";
523 if (rowParams.getFirst("index_name") != null)
524 indexName = rowParams.getFirst("index_name");
525 PreparedQueryObject query = new PreparedQueryObject();
526 query.appendQueryString("Create index if not exists " + indexName + " on " + keyspace + "."
527 + tablename + " (" + fieldName + ");");
529 ResultType result = ResultType.FAILURE;
531 result = MusicCore.nonKeyRelatedPut(query, "eventual");
532 } catch (MusicServiceException ex) {
533 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity
534 .CRITICAL, ErrorTypes.GENERALSERVICEERROR, ex);
535 response.status(Status.BAD_REQUEST);
536 return response.entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
538 if ( result.equals(ResultType.SUCCESS) ) {
539 return response.status(Status.OK).entity(new JsonResponse(result).setMessage("Index Created on " + keyspace+"."+tablename+"."+fieldName).toMap()).build();
541 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Unknown Error in create index.").toMap()).build();
544 EELFLoggerDelegate.mdcRemove("keyspace");
557 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
558 @ApiOperation(value = "Insert Into Table", response = String.class)
559 @Consumes(MediaType.APPLICATION_JSON)
560 @Produces(MediaType.APPLICATION_JSON)
561 public Response insertIntoTable(
562 @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
563 @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
564 @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
565 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
566 @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
567 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
569 @ApiParam(value = "Keyspace Name",
570 required = true) @PathParam("keyspace") String keyspace,
571 @ApiParam(value = "Table Name",
572 required = true) @PathParam("tablename") String tablename) {
574 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
575 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
576 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
577 .setError("one or more path parameters are not set, please check and try again")
580 EELFLoggerDelegate.mdcPut("keyspace","(" + keyspace + ")");
581 PreparedQueryObject queryObject = new PreparedQueryObject();
582 TableMetadata tableInfo = null;
584 tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
585 if(tableInfo == null) {
586 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Table name doesn't exists. Please check the table name.").toMap()).build();
588 } catch (MusicServiceException e) {
589 logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
590 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
592 String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
593 StringBuilder fieldsString = new StringBuilder("(vector_ts,");
595 String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
596 StringBuilder valueString = new StringBuilder("(" + "?" + ",");
597 queryObject.addValue(vectorTs);
599 Map<String, Object> valuesMap = insObj.getValues();
600 if (valuesMap==null) {
601 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
602 .setError("Nothing to insert. No values provided in request.").toMap()).build();
605 String primaryKey = "";
606 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
607 fieldsString.append("" + entry.getKey());
608 Object valueObj = entry.getValue();
609 if (primaryKeyName.equals(entry.getKey())) {
610 primaryKey = entry.getValue() + "";
611 primaryKey = primaryKey.replace("'", "''");
613 DataType colType = null;
615 colType = tableInfo.getColumn(entry.getKey()).getType();
616 } catch(NullPointerException ex) {
617 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey
618 (), AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex);
619 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
622 Object formattedValue = null;
624 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
625 } catch (Exception e) {
626 logger.error(EELFLoggerDelegate.errorLogger,e);
628 valueString.append("?");
630 queryObject.addValue(formattedValue);
632 if (counter == valuesMap.size() - 1) {
633 fieldsString.append(")");
634 valueString.append(")");
636 fieldsString.append(",");
637 valueString.append(",");
639 counter = counter + 1;
643 Map<String, byte[]> objectMap = insObj.getObjectMap();
644 if(objectMap != null) {
645 for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
647 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
648 valueString.replace(valueString.length()-1, valueString.length(), ",");
650 fieldsString.append("" + entry.getKey());
651 byte[] valueObj = entry.getValue();
652 if (primaryKeyName.equals(entry.getKey())) {
653 primaryKey = entry.getValue() + "";
654 primaryKey = primaryKey.replace("'", "''");
656 DataType colType = tableInfo.getColumn(entry.getKey()).getType();
657 ByteBuffer formattedValue = null;
658 if(colType.toString().toLowerCase().contains("blob")) {
659 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
661 valueString.append("?");
662 queryObject.addValue(formattedValue);
663 counter = counter + 1;
664 fieldsString.append(",");
665 valueString.append(",");
669 if(primaryKey == null || primaryKey.length() <= 0) {
670 logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
671 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Some required partition key parts are missing: "+primaryKeyName).toMap()).build();
674 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
675 valueString.replace(valueString.length()-1, valueString.length(), ")");
677 queryObject.appendQueryString("INSERT INTO " + keyspace + "." + tablename + " "
678 + fieldsString + " VALUES " + valueString);
680 String ttl = insObj.getTtl();
681 String timestamp = insObj.getTimestamp();
683 if ((ttl != null) && (timestamp != null)) {
684 logger.info(EELFLoggerDelegate.applicationLogger, "both there");
685 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
686 queryObject.addValue(Integer.parseInt(ttl));
687 queryObject.addValue(Long.parseLong(timestamp));
690 if ((ttl != null) && (timestamp == null)) {
691 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
692 queryObject.appendQueryString(" USING TTL ?");
693 queryObject.addValue(Integer.parseInt(ttl));
696 if ((ttl == null) && (timestamp != null)) {
697 logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
698 queryObject.appendQueryString(" USING TIMESTAMP ?");
699 queryObject.addValue(Long.parseLong(timestamp));
702 queryObject.appendQueryString(";");
704 ReturnType result = null;
705 String consistency = insObj.getConsistencyInfo().get("type");
706 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && insObj.getConsistencyInfo().get("consistency") != null) {
707 if(MusicUtil.isValidConsistency(insObj.getConsistencyInfo().get("consistency"))) {
708 queryObject.setConsistency(insObj.getConsistencyInfo().get("consistency"));
710 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
713 queryObject.setOperation("insert");
715 if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
716 result = MusicCore.eventualPut(queryObject);
717 } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
718 String lockId = insObj.getConsistencyInfo().get("lockId");
720 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
721 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
722 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
723 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
725 result = MusicCore.criticalPut(keyspace, tablename, primaryKey, queryObject, lockId,null);
726 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
727 result = MusicCore.atomicPut(keyspace, tablename, primaryKey, queryObject, null);
729 } catch (Exception ex) {
730 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity
731 .WARN, ErrorTypes.MUSICSERVICEERROR, ex);
732 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
735 logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
736 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
737 }else if(result.getResult() == ResultType.FAILURE) {
738 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result.getResult()).setError(result.getMessage()).toMap()).build();
740 return response.status(Status.OK).entity(new JsonResponse(result.getResult()).setMessage("Insert Successful").toMap()).build();
742 EELFLoggerDelegate.mdcRemove("keyspace");
753 * @throws MusicServiceException
754 * @throws MusicQueryException
758 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
759 @ApiOperation(value = "Update Table", response = String.class)
760 @Consumes(MediaType.APPLICATION_JSON)
761 @Produces(MediaType.APPLICATION_JSON)
762 public Response updateTable(
763 @ApiParam(value = "Major Version",
764 required = true) @PathParam("version") String version,
765 @ApiParam(value = "Minor Version",
766 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
767 @ApiParam(value = "Patch Version",
768 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
769 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
770 @ApiParam(value = "Application namespace",
771 required = true) @HeaderParam(NS) String ns,
772 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
773 JsonUpdate updateObj,
774 @ApiParam(value = "Keyspace Name",
775 required = true) @PathParam("keyspace") String keyspace,
776 @ApiParam(value = "Table Name",
777 required = true) @PathParam("tablename") String tablename,
778 @Context UriInfo info) throws MusicQueryException, MusicServiceException {
780 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
781 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
782 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
783 .setError("one or more path parameters are not set, please check and try again")
786 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
787 long startTime = System.currentTimeMillis();
788 String operationId = UUID.randomUUID().toString(); // just for infoging
790 String consistency = updateObj.getConsistencyInfo().get("type");
792 logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
793 + " update-" + operationId + "-------------------------");
794 // obtain the field value pairs of the update
796 PreparedQueryObject queryObject = new PreparedQueryObject();
797 Map<String, Object> valuesMap = updateObj.getValues();
799 TableMetadata tableInfo;
801 tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
802 } catch (MusicServiceException e) {
803 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
804 .GENERALSERVICEERROR, e);
805 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
807 if (tableInfo == null) {
808 logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+tablename, AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
809 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
810 .setError("Table information not found. Please check input for table name= "
811 + keyspace + "." + tablename).toMap()).build();
813 String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
814 StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
815 queryObject.addValue(vectorTs);
817 for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
818 Object valueObj = entry.getValue();
819 DataType colType = null;
821 colType = tableInfo.getColumn(entry.getKey()).getType();
822 } catch(NullPointerException ex) {
823 logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey(), ex);
824 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
826 Object valueString = null;
828 valueString = MusicUtil.convertToActualDataType(colType, valueObj);
829 } catch (Exception e) {
830 logger.error(EELFLoggerDelegate.errorLogger,e);
832 fieldValueString.append(entry.getKey() + "= ?");
833 queryObject.addValue(valueString);
834 if (counter != valuesMap.size() - 1) {
835 fieldValueString.append(",");
837 counter = counter + 1;
839 String ttl = updateObj.getTtl();
840 String timestamp = updateObj.getTimestamp();
842 queryObject.appendQueryString("UPDATE " + keyspace + "." + tablename + " ");
843 if ((ttl != null) && (timestamp != null)) {
844 logger.info("both there");
845 queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
846 queryObject.addValue(Integer.parseInt(ttl));
847 queryObject.addValue(Long.parseLong(timestamp));
850 if ((ttl != null) && (timestamp == null)) {
851 logger.info("ONLY TTL there");
852 queryObject.appendQueryString(" USING TTL ?");
853 queryObject.addValue(Integer.parseInt(ttl));
856 if ((ttl == null) && (timestamp != null)) {
857 logger.info("ONLY timestamp there");
858 queryObject.appendQueryString(" USING TIMESTAMP ?");
859 queryObject.addValue(Long.parseLong(timestamp));
861 // get the row specifier
862 RowIdentifier rowId = null;
864 rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
865 if(rowId == null || rowId.primarKeyValue.isEmpty()) {
866 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
867 .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();
869 } catch (MusicServiceException ex) {
870 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
871 .GENERALSERVICEERROR, ex);
872 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
875 queryObject.appendQueryString(
876 " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
878 // get the conditional, if any
879 Condition conditionInfo;
880 if (updateObj.getConditions() == null) {
881 conditionInfo = null;
883 // to avoid parsing repeatedly, just send the select query to obtain row
884 PreparedQueryObject selectQuery = new PreparedQueryObject();
885 selectQuery.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + " WHERE "
886 + rowId.rowIdString + ";");
887 selectQuery.addValue(rowId.primarKeyValue);
888 conditionInfo = new Condition(updateObj.getConditions(), selectQuery);
891 ReturnType operationResult = null;
892 long jsonParseCompletionTime = System.currentTimeMillis();
894 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && updateObj.getConsistencyInfo().get("consistency") != null) {
895 if(MusicUtil.isValidConsistency(updateObj.getConsistencyInfo().get("consistency"))) {
896 queryObject.setConsistency(updateObj.getConsistencyInfo().get("consistency"));
898 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
901 queryObject.setOperation("update");
902 if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
903 operationResult = MusicCore.eventualPut(queryObject);
904 } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
905 String lockId = updateObj.getConsistencyInfo().get("lockId");
907 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
908 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
909 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
910 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
912 operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
913 queryObject, lockId, conditionInfo);
914 } else if (consistency.equalsIgnoreCase("atomic_delete_lock")) {
915 // this function is mainly for the benchmarks
917 operationResult = MusicCore.atomicPutWithDeleteLock(keyspace, tablename,
918 rowId.primarKeyValue, queryObject, conditionInfo);
919 } catch (MusicLockingException e) {
920 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN,
921 ErrorTypes.GENERALSERVICEERROR, e);
922 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
924 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
926 operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
927 queryObject, conditionInfo);
928 } catch (MusicLockingException e) {
929 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, e);
930 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
932 } else if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
933 operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
935 long actualUpdateCompletionTime = System.currentTimeMillis();
937 long endTime = System.currentTimeMillis();
938 String timingString = "Time taken in ms for Music " + consistency + " update-" + operationId
939 + ":" + "|total operation time:" + (endTime - startTime)
940 + "|json parsing time:" + (jsonParseCompletionTime - startTime)
941 + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
944 if (operationResult != null && operationResult.getTimingInfo() != null) {
945 String lockManagementTime = operationResult.getTimingInfo();
946 timingString = timingString + lockManagementTime;
948 logger.info(EELFLoggerDelegate.applicationLogger, timingString);
950 if (operationResult==null) {
951 logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
952 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
954 if ( operationResult.getResult() == ResultType.SUCCESS ) {
955 return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
957 logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
958 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(operationResult.getResult()).setError(operationResult.getMessage()).toMap()).build();
961 EELFLoggerDelegate.mdcRemove("keyspace");
972 * @throws MusicServiceException
973 * @throws MusicQueryException
977 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
978 @ApiOperation(value = "Delete From table", response = String.class)
979 @Consumes(MediaType.APPLICATION_JSON)
980 @Produces(MediaType.APPLICATION_JSON)
981 public Response deleteFromTable(
982 @ApiParam(value = "Major Version",
983 required = true) @PathParam("version") String version,
984 @ApiParam(value = "Minor Version",
985 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
986 @ApiParam(value = "Patch Version",
987 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
988 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
989 @ApiParam(value = "Application namespace",
990 required = true) @HeaderParam(NS) String ns,
991 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
993 @ApiParam(value = "Keyspace Name",
994 required = true) @PathParam("keyspace") String keyspace,
995 @ApiParam(value = "Table Name",
996 required = true) @PathParam("tablename") String tablename,
997 @Context UriInfo info) throws MusicQueryException, MusicServiceException {
999 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1000 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1001 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1002 .setError("one or more path parameters are not set, please check and try again")
1005 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1006 if(delObj == null) {
1007 logger.error(EELFLoggerDelegate.errorLogger,"Required HTTP Request body is missing.", AppMessages.MISSINGDATA ,ErrorSeverity.WARN, ErrorTypes.DATAERROR);
1008 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Required HTTP Request body is missing.").toMap()).build();
1010 PreparedQueryObject queryObject = new PreparedQueryObject();
1011 StringBuilder columnString = new StringBuilder();
1014 List<String> columnList = delObj.getColumns();
1015 if (columnList != null) {
1016 for (String column : columnList) {
1017 columnString.append(column);
1018 if (counter != columnList.size() - 1)
1019 columnString.append(",");
1020 counter = counter + 1;
1024 // get the row specifier
1025 RowIdentifier rowId = null;
1027 rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1028 } catch (MusicServiceException ex) {
1029 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
1030 .GENERALSERVICEERROR, ex);
1031 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1033 String rowSpec = rowId.rowIdString.toString();
1035 if ((columnList != null) && (!rowSpec.isEmpty())) {
1036 queryObject.appendQueryString("DELETE " + columnString + " FROM " + keyspace + "."
1037 + tablename + " WHERE " + rowSpec + ";");
1040 if ((columnList == null) && (!rowSpec.isEmpty())) {
1041 queryObject.appendQueryString("DELETE FROM " + keyspace + "." + tablename + " WHERE "
1045 if ((columnList != null) && (rowSpec.isEmpty())) {
1046 queryObject.appendQueryString(
1047 "DELETE " + columnString + " FROM " + keyspace + "." + rowSpec + ";");
1049 // get the conditional, if any
1050 Condition conditionInfo;
1051 if (delObj.getConditions() == null) {
1052 conditionInfo = null;
1054 // to avoid parsing repeatedly, just send the select query to
1056 PreparedQueryObject selectQuery = new PreparedQueryObject();
1057 selectQuery.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + " WHERE "
1058 + rowId.rowIdString + ";");
1059 selectQuery.addValue(rowId.primarKeyValue);
1060 conditionInfo = new Condition(delObj.getConditions(), selectQuery);
1063 String consistency = delObj.getConsistencyInfo().get("type");
1066 if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && delObj.getConsistencyInfo().get("consistency")!=null) {
1067 if(MusicUtil.isValidConsistency(delObj.getConsistencyInfo().get("consistency"))) {
1068 queryObject.setConsistency(delObj.getConsistencyInfo().get("consistency"));
1070 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR)
1071 .setError("Invalid Consistency type").toMap()).build();
1074 ReturnType operationResult = null;
1075 queryObject.setOperation("delete");
1077 if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
1078 operationResult = MusicCore.eventualPut(queryObject);
1079 else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1080 String lockId = delObj.getConsistencyInfo().get("lockId");
1081 if(lockId == null) {
1082 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1083 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1084 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1085 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1087 operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
1088 queryObject, lockId, conditionInfo);
1089 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1090 operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
1091 queryObject, conditionInfo);
1092 } else if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
1093 operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
1095 } catch (MusicLockingException e) {
1096 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, e);
1097 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1098 .setError("Unable to perform Delete operation. Exception from music").toMap()).build();
1100 if (operationResult==null) {
1101 logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1102 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
1104 if (operationResult.getResult().equals(ResultType.SUCCESS)) {
1105 return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
1107 logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1108 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(operationResult.getMessage()).toMap()).build();
1111 EELFLoggerDelegate.mdcRemove("keyspace");
1123 @Path("/{keyspace: .*}/tables/{tablename: .*}")
1124 @ApiOperation(value = "Drop Table", response = String.class)
1125 @Produces(MediaType.APPLICATION_JSON)
1126 public Response dropTable(
1127 @ApiParam(value = "Major Version",
1128 required = true) @PathParam("version") String version,
1129 @ApiParam(value = "Minor Version",
1130 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1131 @ApiParam(value = "Patch Version",
1132 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1133 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1134 @ApiParam(value = "Application namespace",
1135 required = true) @HeaderParam(NS) String ns,
1136 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1137 @ApiParam(value = "Keyspace Name",
1138 required = true) @PathParam("keyspace") String keyspace,
1139 @ApiParam(value = "Table Name",
1140 required = true) @PathParam("tablename") String tablename) throws Exception {
1142 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1143 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1144 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1145 .setError("one or more path parameters are not set, please check and try again")
1148 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1149 String consistency = "eventual";// for now this needs only eventual consistency
1150 PreparedQueryObject query = new PreparedQueryObject();
1151 query.appendQueryString("DROP TABLE " + keyspace + "." + tablename + ";");
1153 return response.status(Status.OK).entity(new JsonResponse(MusicCore.nonKeyRelatedPut(query, consistency)).toMap()).build();
1154 } catch (MusicServiceException ex) {
1155 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.MISSINGINFO ,ErrorSeverity.WARN, ErrorTypes
1156 .GENERALSERVICEERROR);
1157 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1160 EELFLoggerDelegate.mdcRemove("keyspace");
1173 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows/criticalget")
1174 @ApiOperation(value = "Select Critical", response = Map.class)
1175 @Consumes(MediaType.APPLICATION_JSON)
1176 @Produces(MediaType.APPLICATION_JSON)
1177 public Response selectCritical(
1178 @ApiParam(value = "Major Version",
1179 required = true) @PathParam("version") String version,
1180 @ApiParam(value = "Minor Version",
1181 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1182 @ApiParam(value = "Patch Version",
1183 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1184 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1185 @ApiParam(value = "Application namespace",
1186 required = true) @HeaderParam(NS) String ns,
1187 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1189 @ApiParam(value = "Keyspace Name",
1190 required = true) @PathParam("keyspace") String keyspace,
1191 @ApiParam(value = "Table Name",
1192 required = true) @PathParam("tablename") String tablename,
1193 @Context UriInfo info) throws Exception {
1195 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1196 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1197 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1198 .setError("one or more path parameters are not set, please check and try again")
1201 EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1202 String lockId = selObj.getConsistencyInfo().get("lockId");
1203 PreparedQueryObject queryObject = new PreparedQueryObject();
1204 RowIdentifier rowId = null;
1206 rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1207 } catch (MusicServiceException ex) {
1208 logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes
1209 .GENERALSERVICEERROR, ex);
1210 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1212 queryObject.appendQueryString(
1213 "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowId.rowIdString + ";");
1215 ResultSet results = null;
1217 String consistency = selObj.getConsistencyInfo().get("type");
1219 if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1220 if(lockId == null) {
1221 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1222 + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1223 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1224 + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1226 results = MusicCore.criticalGet(keyspace, tablename, rowId.primarKeyValue, queryObject,lockId);
1227 } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1228 results = MusicCore.atomicGet(keyspace, tablename, rowId.primarKeyValue, queryObject);
1230 }catch(Exception ex) {
1231 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1234 if(results!=null && results.getAvailableWithoutFetching() >0) {
1235 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1237 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setError("No data found").toMap()).build();
1239 EELFLoggerDelegate.mdcRemove("keyspace");
1252 @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
1253 @ApiOperation(value = "Select All or Select Specific", response = Map.class)
1254 @Produces(MediaType.APPLICATION_JSON)
1255 public Response select(
1256 @ApiParam(value = "Major Version",
1257 required = true) @PathParam("version") String version,
1258 @ApiParam(value = "Minor Version",
1259 required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1260 @ApiParam(value = "Patch Version",
1261 required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1262 @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1263 @ApiParam(value = "Application namespace",
1264 required = true) @HeaderParam(NS) String ns,
1265 @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1266 @ApiParam(value = "Keyspace Name",
1267 required = true) @PathParam("keyspace") String keyspace,
1268 @ApiParam(value = "Table Name",
1269 required = true) @PathParam("tablename") String tablename,
1270 @Context UriInfo info) throws Exception {
1272 ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1273 if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1274 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1275 .setError("one or more path parameters are not set, please check and try again")
1278 EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspace + " ) ");
1279 PreparedQueryObject queryObject = new PreparedQueryObject();
1281 if (info.getQueryParameters().isEmpty()) { // select all
1282 queryObject.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + ";");
1284 int limit = -1; // do not limit the number of results
1286 queryObject = selectSpecificQuery(keyspace, tablename, info, limit);
1287 } catch (MusicServiceException ex) {
1288 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN,
1289 ErrorTypes.GENERALSERVICEERROR, ex);
1290 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1294 ResultSet results = MusicCore.get(queryObject);
1295 if(results.getAvailableWithoutFetching() >0) {
1296 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1298 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).setError("No data found").toMap()).build();
1299 } catch (MusicServiceException ex) {
1300 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.ERROR,
1301 ErrorTypes.MUSICSERVICEERROR, ex);
1302 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1305 EELFLoggerDelegate.mdcRemove("keyspace");
1316 * @throws MusicServiceException
1318 public PreparedQueryObject selectSpecificQuery(String keyspace,
1319 String tablename, UriInfo info, int limit)
1320 throws MusicServiceException {
1321 PreparedQueryObject queryObject = new PreparedQueryObject();
1322 StringBuilder rowIdString = getRowIdentifier(keyspace,
1323 tablename,info.getQueryParameters(),queryObject).rowIdString;
1324 queryObject.appendQueryString(
1325 "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowIdString);
1327 queryObject.appendQueryString(" LIMIT " + limit);
1329 queryObject.appendQueryString(";");
1338 * @param queryObject
1340 * @throws MusicServiceException
1342 private RowIdentifier getRowIdentifier(String keyspace, String tablename,
1343 MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
1344 throws MusicServiceException {
1345 StringBuilder rowSpec = new StringBuilder();
1347 TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
1348 if (tableInfo == null) {
1349 logger.error(EELFLoggerDelegate.errorLogger,
1350 "Table information not found. Please check input for table name= "
1351 + keyspace + "." + tablename);
1352 throw new MusicServiceException(
1353 "Table information not found. Please check input for table name= "
1354 + keyspace + "." + tablename);
1356 StringBuilder primaryKey = new StringBuilder();
1357 for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
1358 String keyName = entry.getKey();
1359 List<String> valueList = entry.getValue();
1360 String indValue = valueList.get(0);
1361 DataType colType = null;
1362 Object formattedValue = null;
1364 colType = tableInfo.getColumn(entry.getKey()).getType();
1365 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
1366 } catch (Exception e) {
1367 logger.error(EELFLoggerDelegate.errorLogger,e);
1369 if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
1370 primaryKey.append(indValue);
1372 rowSpec.append(keyName + "= ?");
1373 queryObject.addValue(formattedValue);
1374 if (counter != rowParams.size() - 1) {
1375 rowSpec.append(" AND ");
1377 counter = counter + 1;
1379 return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);