CADI and a few small updates.
[music.git] / src / main / java / org / onap / music / rest / RestMusicDataAPI.java
1 /*
2  * ============LICENSE_START==========================================
3  * org.onap.music
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
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  *
21  * ============LICENSE_END=============================================
22  * ====================================================================
23  */
24
25 package org.onap.music.rest;
26
27 import java.nio.ByteBuffer;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.UUID;
31
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;
48
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;
70
71 import com.datastax.driver.core.DataType;
72 import com.datastax.driver.core.ResultSet;
73 import com.datastax.driver.core.TableMetadata;
74
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;
80
81 /* Version 2 Class */
82 //@Path("/v{version: [0-9]+}/keyspaces")
83 @Path("/v2/keyspaces")
84 @Api(value = "Data Api")
85 public class RestMusicDataAPI {
86     /*
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
94      *
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)
101      *
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)
106      *
107      */
108
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";
114
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
121
122         public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
123                         PreparedQueryObject queryObject) {
124             this.primarKeyValue = primaryKeyValue;
125             this.rowIdString = rowIdString;
126             this.queryObject = queryObject;
127         }
128     }
129
130
131     /**
132      * Create Keyspace REST
133      *
134      * @param kspObject
135      * @param keyspaceName
136      * @return
137      * @throws Exception
138      */
139     @POST
140     @Path("/{name}")
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) {
153         try {
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);
159                 
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();
163                 }
164         
165                 String consistency = MusicUtil.EVENTUAL;// for now this needs only eventual consistency
166         
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"));
171                     else
172                         return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
173                 }
174                 long start = System.currentTimeMillis();
175                 Map<String, Object> replicationInfo = kspObject.getReplicationInfo();
176                 String repString = null;
177                 try {
178                     repString = "{" + MusicUtil.jsonMaptoSqlString(replicationInfo, ",") + "}";
179                 } catch (Exception e) {
180                     logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGDATA  ,ErrorSeverity
181                         .CRITICAL, ErrorTypes.DATAERROR, e);
182         
183                 }
184                 queryObject.appendQueryString(
185                                 "CREATE KEYSPACE " + keyspaceName + " WITH replication = " + repString);
186                 if (kspObject.getDurabilityOfWrites() != null) {
187                     queryObject.appendQueryString(
188                                     " AND durable_writes = " + kspObject.getDurabilityOfWrites());
189                 }
190         
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));
195         
196                 ResultType result = ResultType.FAILURE;
197                 try {
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();
204                 }
205         
206                 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Created").toMap()).build();
207             } else {
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();
212             }
213         } finally {
214             EELFLoggerDelegate.mdcRemove("keyspace");
215         }
216         
217     }
218
219     /**
220      *
221      * @param kspObject
222      * @param keyspaceName
223      * @return
224      * @throws Exception
225      */
226     @DELETE
227     @Path("/{name}")
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 {
238         try {
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();
249                 }
250                 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Deleted").toMap()).build();
251             } else {
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();
256             }
257         } finally {
258             EELFLoggerDelegate.mdcRemove("keyspace");
259         }
260     }
261
262     /**
263      *
264      * @param tableObj
265      * @param version
266      * @param keyspace
267      * @param tablename
268      * @param headers
269      * @return
270      * @throws Exception -
271      */
272     @POST
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")
280     })
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,
288         JsonTable tableObj,
289         @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
290         @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename) throws Exception {
291         try {
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 + "'")
297                             .toMap()).build();
298             }
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;
308             }
309             primaryKey = tableObj.getPrimaryKey(); // get primaryKey if available
310
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();
317             }
318
319             StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
320             int counter = 0;
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();
325                 } else {
326                     if (counter == 0 )  fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
327                     else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + "");
328                 }
329
330                 if (counter != (fields.size() - 1) ) {
331                     counter = counter + 1; 
332                 } else {
333             
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)
341                                 .toMap()).build();
342                         }
343
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("[)]+", "");
350                             } else {
351                                 partitionKey=primaryKey;
352                                 partitionKey=partitionKey.replaceAll("[\\)]+","");
353                                 partitionKey=partitionKey.replaceAll("[\\(]+","");
354                                 clusterKey="";
355                             }
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);
366                             }
367                             clusterKey = clusterKey.trim();
368                             if (clusterKey.equals(",") ) clusterKey=""; // print error if needed    ( ... ),)
369                         }
370
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)
378                                 .toMap()).build();
379
380                         }
381
382                         if (partitionKey.isEmpty() )  primaryKey="";
383                         else  if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey  + ")";
384                         else  primaryKey=" (" + partitionKey + ")," + clusterKey;
385
386                 
387                         if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
388
389                     } else { // end of length > 0
390                     
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+ ")")
397                                 .toMap()).build();
398                         }
399
400                         if (partitionKey.isEmpty() )  primaryKey="";
401                         else  if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey  + ")";
402                         else  primaryKey=" (" + partitionKey + ")," + clusterKey;
403
404                         if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
405                     }
406                     fieldsString.append(")");
407
408                 } // end of last field check
409
410             } // end of for each
411             // information about the name-value style properties
412             Map<String, Object> propertiesMap = tableObj.getProperties();
413             StringBuilder propertiesString = new StringBuilder();
414             if (propertiesMap != null) {
415                 counter = 0;
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, ",") + "}";
425                     }
426
427                     propertiesString.append(entry.getKey() + "=" + value + "");
428                     if (counter != propertiesMap.size() - 1)
429                         propertiesString.append(" AND ");
430
431                     counter = counter + 1;
432                 }
433             }
434
435             String clusteringOrder = tableObj.getClusteringOrder();
436
437             if (clusteringOrder != null && !(clusteringOrder.isEmpty())) {
438                 String[] arrayClusterOrder = clusteringOrder.split("[,]+");
439
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"))) {
443                         continue;
444                     } else {
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+".")
448                         .toMap()).build();
449                     }
450                     // add validation for column names in cluster key
451                 }
452
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);
458                     } else {
459                         propertiesString.append(clusteringOrder);
460                     }
461                 } else {
462                     logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty ");
463                 }
464             } //if non empty
465
466             queryObject.appendQueryString(
467                 "CREATE TABLE " + keyspace + "." + tablename + " " + fieldsString);
468
469
470             if (propertiesString != null &&  propertiesString.length()>0 )
471                 queryObject.appendQueryString(" WITH " + propertiesString);
472             queryObject.appendQueryString(";");
473             ResultType result = ResultType.FAILURE;
474             try {
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();
480             }
481             if ( result.equals(ResultType.FAILURE) ) {
482                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Creating Table " + tablename).toMap()).build();
483             }
484             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("TableName " + tablename.trim() + " Created under keyspace " + keyspace.trim()).toMap()).build();
485         } finally {
486             EELFLoggerDelegate.mdcRemove("keyspace");
487         }
488     }
489
490     /**
491      *
492      * @param keyspace
493      * @param tablename
494      * @param fieldName
495      * @param info
496      * @throws Exception
497      */
498     @POST
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 {
513         try {
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")
518                     .toMap()).build();
519             }
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 + ");");
528
529             ResultType result = ResultType.FAILURE;
530             try {
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();
537             }
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();
540             } else {
541                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Unknown Error in create index.").toMap()).build();
542             }
543         } finally {
544             EELFLoggerDelegate.mdcRemove("keyspace");
545         }
546     }
547
548     /**
549      *
550      * @param insObj
551      * @param keyspace
552      * @param tablename
553      * @return
554      * @throws Exception
555      */
556     @POST
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,
568         JsonInsert insObj,
569         @ApiParam(value = "Keyspace Name",
570             required = true) @PathParam("keyspace") String keyspace,
571         @ApiParam(value = "Table Name",
572             required = true) @PathParam("tablename") String tablename) {
573         try {
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")
578                     .toMap()).build();
579             }
580             EELFLoggerDelegate.mdcPut("keyspace","(" + keyspace + ")");
581             PreparedQueryObject queryObject = new PreparedQueryObject();
582             TableMetadata tableInfo = null;
583             try {
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();
587                 }
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();
591             }
592             String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
593             StringBuilder fieldsString = new StringBuilder("(vector_ts,");
594             String vectorTs =
595                             String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
596             StringBuilder valueString = new StringBuilder("(" + "?" + ",");
597             queryObject.addValue(vectorTs);
598             
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();
603             }
604             int counter = 0;
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("'", "''");
612                 }
613                 DataType colType = null;
614                 try {
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();
620                 }
621
622                 Object formattedValue = null;
623                 try {
624                     formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
625                 } catch (Exception e) {
626                     logger.error(EELFLoggerDelegate.errorLogger,e);
627                 }
628                 valueString.append("?");
629
630                 queryObject.addValue(formattedValue);
631
632                 if (counter == valuesMap.size() - 1) {
633                     fieldsString.append(")");
634                     valueString.append(")");
635                 } else {
636                     fieldsString.append(",");
637                     valueString.append(",");
638                 }
639                 counter = counter + 1;
640             }
641
642             //blobs..
643             Map<String, byte[]> objectMap = insObj.getObjectMap();
644             if(objectMap != null) {
645                 for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
646                     if(counter > 0) {
647                         fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
648                         valueString.replace(valueString.length()-1, valueString.length(), ",");
649                     }
650                     fieldsString.append("" + entry.getKey());
651                     byte[] valueObj = entry.getValue();
652                     if (primaryKeyName.equals(entry.getKey())) {
653                         primaryKey = entry.getValue() + "";
654                         primaryKey = primaryKey.replace("'", "''");
655                     }
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);
660                     }
661                     valueString.append("?");
662                     queryObject.addValue(formattedValue);
663                     counter = counter + 1;
664                     fieldsString.append(",");
665                     valueString.append(",");
666                 } 
667             }
668
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();
672             }
673
674             fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
675             valueString.replace(valueString.length()-1, valueString.length(), ")");
676
677             queryObject.appendQueryString("INSERT INTO " + keyspace + "." + tablename + " "
678                             + fieldsString + " VALUES " + valueString);
679
680             String ttl = insObj.getTtl();
681             String timestamp = insObj.getTimestamp();
682
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));
688             }
689
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));
694             }
695
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));
700             }
701
702             queryObject.appendQueryString(";");
703
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"));
709                 } else {
710                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
711                 }
712             }
713             queryObject.setOperation("insert");
714             try {
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");
719                     if(lockId == null) {
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();
724                     }
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);
728                 }
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();
733             }
734             if (result==null) {
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();
739             }
740             return response.status(Status.OK).entity(new JsonResponse(result.getResult()).setMessage("Insert Successful").toMap()).build();
741         } finally {
742             EELFLoggerDelegate.mdcRemove("keyspace");
743         }
744     }
745
746     /**
747      *
748      * @param insObj
749      * @param keyspace
750      * @param tablename
751      * @param info
752      * @return
753      * @throws MusicServiceException 
754      * @throws MusicQueryException 
755      * @throws Exception
756      */
757     @PUT
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 {
779         try {
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")
784                     .toMap()).build();
785             }
786             EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
787             long startTime = System.currentTimeMillis();
788             String operationId = UUID.randomUUID().toString();  // just for infoging
789                                                                 // purposes.
790             String consistency = updateObj.getConsistencyInfo().get("type");
791
792             logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
793                 + " update-" + operationId + "-------------------------");
794             // obtain the field value pairs of the update
795
796             PreparedQueryObject queryObject = new PreparedQueryObject();
797             Map<String, Object> valuesMap = updateObj.getValues();
798
799             TableMetadata tableInfo;
800             try {
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();
806             }
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();
812             }
813             String vectorTs = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
814             StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
815             queryObject.addValue(vectorTs);
816             int counter = 0;
817             for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
818                 Object valueObj = entry.getValue();
819                 DataType colType = null;
820                 try {
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();
825                 }
826                 Object valueString = null;
827                 try {
828                     valueString = MusicUtil.convertToActualDataType(colType, valueObj);
829                 } catch (Exception e) {
830                     logger.error(EELFLoggerDelegate.errorLogger,e);
831                 }
832                 fieldValueString.append(entry.getKey() + "= ?");
833                 queryObject.addValue(valueString);
834                 if (counter != valuesMap.size() - 1) {
835                     fieldValueString.append(",");
836                 }    
837                 counter = counter + 1;
838             }
839             String ttl = updateObj.getTtl();
840             String timestamp = updateObj.getTimestamp();
841
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));
848             }
849
850             if ((ttl != null) && (timestamp == null)) {
851                 logger.info("ONLY TTL there");
852                 queryObject.appendQueryString(" USING TTL ?");
853                 queryObject.addValue(Integer.parseInt(ttl));
854             }
855
856             if ((ttl == null) && (timestamp != null)) {
857                 logger.info("ONLY timestamp there");
858                 queryObject.appendQueryString(" USING TIMESTAMP ?");
859                 queryObject.addValue(Long.parseLong(timestamp));
860             }
861             // get the row specifier
862             RowIdentifier rowId = null;
863             try {
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();
868                 }
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();
873             }
874
875             queryObject.appendQueryString(
876                 " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
877
878             // get the conditional, if any
879             Condition conditionInfo;
880             if (updateObj.getConditions() == null) {
881                 conditionInfo = null;
882             } else {
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);
889             }
890
891             ReturnType operationResult = null;
892             long jsonParseCompletionTime = System.currentTimeMillis();
893
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"));
897                 } else {
898                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
899                 }
900             }
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");
906                 if(lockId == null) {
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();
911                 }
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
916                 try {
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();
923                 }
924             } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
925                 try {
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();
931                 }
932             } else if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
933                 operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
934             }
935             long actualUpdateCompletionTime = System.currentTimeMillis();
936
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)
942                 + "|";
943
944             if (operationResult != null && operationResult.getTimingInfo() != null) {
945                 String lockManagementTime = operationResult.getTimingInfo();
946                 timingString = timingString + lockManagementTime;
947             }
948             logger.info(EELFLoggerDelegate.applicationLogger, timingString);
949
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();
953             }
954             if ( operationResult.getResult() == ResultType.SUCCESS ) {
955                 return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
956             } else {
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();
959             }
960         } finally {
961             EELFLoggerDelegate.mdcRemove("keyspace");
962         }
963     }
964
965     /**
966      *
967      * @param delObj
968      * @param keyspace
969      * @param tablename
970      * @param info
971      * @return
972      * @throws MusicServiceException 
973      * @throws MusicQueryException 
974      * @throws Exception
975      */
976     @DELETE
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,
992         JsonDelete delObj,
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 {
998         try {
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")
1003                     .toMap()).build();
1004             }
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();
1009             }
1010             PreparedQueryObject queryObject = new PreparedQueryObject();
1011             StringBuilder columnString = new StringBuilder();
1012
1013             int counter = 0;
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;
1021                 }
1022             }
1023
1024             // get the row specifier
1025             RowIdentifier rowId = null;
1026             try {
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();
1032             }
1033             String rowSpec = rowId.rowIdString.toString();
1034
1035             if ((columnList != null) && (!rowSpec.isEmpty())) {
1036                 queryObject.appendQueryString("DELETE " + columnString + " FROM " + keyspace + "."
1037                                 + tablename + " WHERE " + rowSpec + ";");
1038             }
1039
1040             if ((columnList == null) && (!rowSpec.isEmpty())) {
1041                 queryObject.appendQueryString("DELETE FROM " + keyspace + "." + tablename + " WHERE "
1042                                 + rowSpec + ";");
1043             }
1044
1045             if ((columnList != null) && (rowSpec.isEmpty())) {
1046                 queryObject.appendQueryString(
1047                                 "DELETE " + columnString + " FROM " + keyspace + "." + rowSpec + ";");
1048             }
1049             // get the conditional, if any
1050             Condition conditionInfo;
1051             if (delObj.getConditions() == null) {
1052                 conditionInfo = null;
1053             } else {
1054                 // to avoid parsing repeatedly, just send the select query to
1055                 // obtain row
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);
1061             }
1062
1063             String consistency = delObj.getConsistencyInfo().get("type");
1064
1065
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"));
1069                 } else {
1070                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR)
1071                         .setError("Invalid Consistency type").toMap()).build();
1072                 }
1073             }
1074             ReturnType operationResult = null;
1075             queryObject.setOperation("delete");
1076             try {
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();
1086                     }
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);
1094                 }
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();
1099             }
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();
1103             }
1104             if (operationResult.getResult().equals(ResultType.SUCCESS)) {
1105                 return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
1106             } else {
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();
1109             }
1110         } finally {
1111             EELFLoggerDelegate.mdcRemove("keyspace");
1112         }
1113     }
1114
1115     /**
1116      *
1117      * @param tabObj
1118      * @param keyspace
1119      * @param tablename
1120      * @throws Exception
1121      */
1122     @DELETE
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 {
1141         try {
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")
1146                     .toMap()).build();
1147             }
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 + ";");
1152             try {
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();
1158             }
1159         } finally {
1160             EELFLoggerDelegate.mdcRemove("keyspace");
1161         }
1162     }
1163
1164     /**
1165      *
1166      * @param selObj
1167      * @param keyspace
1168      * @param tablename
1169      * @param info
1170      * @return
1171      */
1172     @PUT
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,
1188         JsonInsert selObj,
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 {
1194         try {
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")
1199                     .toMap()).build();
1200             }
1201             EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1202             String lockId = selObj.getConsistencyInfo().get("lockId");
1203             PreparedQueryObject queryObject = new PreparedQueryObject();
1204             RowIdentifier rowId = null;
1205             try {
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();
1211             }
1212             queryObject.appendQueryString(
1213                 "SELECT *  FROM " + keyspace + "." + tablename + " WHERE " + rowId.rowIdString + ";");
1214
1215             ResultSet results = null;
1216
1217             String consistency = selObj.getConsistencyInfo().get("type");
1218             try {
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();
1225                 }
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);
1229             }
1230             }catch(Exception ex) {
1231                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1232             }
1233             
1234             if(results!=null && results.getAvailableWithoutFetching() >0) {
1235                 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1236             }
1237             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setError("No data found").toMap()).build();
1238         } finally {
1239             EELFLoggerDelegate.mdcRemove("keyspace");
1240         }
1241     }
1242
1243     /**
1244      *
1245      * @param keyspace
1246      * @param tablename
1247      * @param info
1248      * @return
1249      * @throws Exception
1250      */
1251     @GET
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 {
1271         try { 
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")
1276                     .toMap()).build();
1277             }
1278             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspace + " ) ");
1279             PreparedQueryObject queryObject = new PreparedQueryObject();
1280
1281             if (info.getQueryParameters().isEmpty()) { // select all
1282                 queryObject.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + ";");
1283             } else {
1284                 int limit = -1; // do not limit the number of results
1285                 try {
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();
1291                 }
1292             }
1293             try {
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();
1297                 }
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();
1303             }
1304         } finally {
1305             EELFLoggerDelegate.mdcRemove("keyspace");
1306         }
1307     }
1308
1309     /**
1310      *
1311      * @param keyspace
1312      * @param tablename
1313      * @param info
1314      * @param limit
1315      * @return
1316      * @throws MusicServiceException
1317      */
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);
1326         if (limit != -1) {
1327             queryObject.appendQueryString(" LIMIT " + limit);
1328         }
1329         queryObject.appendQueryString(";");
1330         return queryObject;
1331     }
1332
1333     /**
1334      *
1335      * @param keyspace
1336      * @param tablename
1337      * @param rowParams
1338      * @param queryObject
1339      * @return
1340      * @throws MusicServiceException
1341      */
1342     private RowIdentifier getRowIdentifier(String keyspace, String tablename,
1343         MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
1344         throws MusicServiceException {
1345         StringBuilder rowSpec = new StringBuilder();
1346         int counter = 0;
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);
1355         }
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;
1363             try {
1364                 colType = tableInfo.getColumn(entry.getKey()).getType();
1365                 formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
1366             } catch (Exception e) {
1367                 logger.error(EELFLoggerDelegate.errorLogger,e);
1368             }
1369             if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) {
1370                 primaryKey.append(indValue);
1371             }
1372             rowSpec.append(keyName + "= ?");
1373             queryObject.addValue(formattedValue);
1374             if (counter != rowParams.size() - 1) {
1375                 rowSpec.append(" AND ");
1376             }
1377             counter = counter + 1;
1378         }
1379         return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);
1380     }
1381 }