dfcf0bdb8f6c6e296e07ea855482087e838872fd
[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.mindrot.jbcrypt.BCrypt;
51 import org.onap.music.authentication.CachingUtil;
52 import org.onap.music.authentication.MusicAAFAuthentication;
53 import org.onap.music.authentication.MusicAuthenticator;
54 import org.onap.music.authentication.MusicAuthenticator.Operation;
55 import org.onap.music.datastore.PreparedQueryObject;
56 import org.onap.music.datastore.jsonobjects.JsonDelete;
57 import org.onap.music.datastore.jsonobjects.JsonInsert;
58 import org.onap.music.datastore.jsonobjects.JsonKeySpace;
59 import org.onap.music.datastore.jsonobjects.JsonTable;
60 import org.onap.music.datastore.jsonobjects.JsonUpdate;
61 import org.onap.music.eelf.logging.EELFLoggerDelegate;
62 import org.onap.music.exceptions.MusicLockingException;
63 import org.onap.music.exceptions.MusicQueryException;
64 import org.onap.music.eelf.logging.format.AppMessages;
65 import org.onap.music.eelf.logging.format.ErrorSeverity;
66 import org.onap.music.eelf.logging.format.ErrorTypes;
67 import org.onap.music.exceptions.MusicServiceException;
68 import org.onap.music.main.MusicCore;
69 import org.onap.music.datastore.Condition;
70 import org.onap.music.datastore.MusicDataStoreHandle;
71 import org.onap.music.main.MusicUtil;
72 import org.onap.music.main.ResultType;
73 import org.onap.music.main.ReturnType;
74 import org.onap.music.response.jsonobjects.JsonResponse;
75
76 import com.datastax.driver.core.DataType;
77 import com.datastax.driver.core.ResultSet;
78 import com.datastax.driver.core.Row;
79 import com.datastax.driver.core.TableMetadata;
80
81 import io.swagger.annotations.Api;
82 import io.swagger.annotations.ApiOperation;
83 import io.swagger.annotations.ApiParam;
84 import io.swagger.annotations.ApiResponses;
85 import io.swagger.annotations.ApiResponse;
86
87 /* Version 2 Class */
88 //@Path("/v{version: [0-9]+}/keyspaces")
89 @Path("/v2/keyspaces")
90 @Api(value = "Data Api")
91 public class RestMusicDataAPI {
92     /*
93      * Header values for Versioning X-minorVersion *** - Used to request or communicate a MINOR
94      * version back from the client to the server, and from the server back to the client - This
95      * will be the MINOR version requested by the client, or the MINOR version of the last MAJOR
96      * version (if not specified by the client on the request) - Contains a single position value
97      * (e.g. if the full version is 1.24.5, X-minorVersion = "24") - Is optional for the client on
98      * request; however, this header should be provided if the client needs to take advantage of
99      * MINOR incremented version functionality - Is mandatory for the server on response
100      *
101      *** X-patchVersion *** - Used only to communicate a PATCH version in a response for
102      * troubleshooting purposes only, and will not be provided by the client on request - This will
103      * be the latest PATCH version of the MINOR requested by the client, or the latest PATCH version
104      * of the MAJOR (if not specified by the client on the request) - Contains a single position
105      * value (e.g. if the full version is 1.24.5, X-patchVersion = "5") - Is mandatory for the
106      * server on response  (CURRENTLY NOT USED)
107      *
108      *** X-latestVersion *** - Used only to communicate an API's latest version - Is mandatory for the
109      * server on response, and shall include the entire version of the API (e.g. if the full version
110      * is 1.24.5, X-latestVersion = "1.24.5") - Used in the response to inform clients that they are
111      * not using the latest version of the API (CURRENTLY NOT USED)
112      *
113      */
114
115     private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicDataAPI.class);
116     private static final String XMINORVERSION = "X-minorVersion";
117     private static final String XPATCHVERSION = "X-patchVersion";
118     private static final String NS = "ns";
119     private static final String VERSION = "v2";
120     private MusicAuthenticator authenticator = new MusicAAFAuthentication();
121     // Set to true in env like ONAP. Where access to creating and dropping keyspaces exist.    
122     private static final boolean KEYSPACE_ACTIVE = false;
123
124     private class RowIdentifier {
125         public String primarKeyValue;
126         public StringBuilder rowIdString;
127         @SuppressWarnings("unused")
128         public PreparedQueryObject queryObject;// the string with all the row
129                                                // identifiers separated by AND
130
131         public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
132                         PreparedQueryObject queryObject) {
133             this.primarKeyValue = primaryKeyValue;
134             this.rowIdString = rowIdString;
135             this.queryObject = queryObject;
136         }
137     }
138
139
140     /**
141      * Create Keyspace REST
142      *
143      * @param kspObject
144      * @param keyspaceName
145      * @return
146      * @throws Exception
147      */
148     @POST
149     @Path("/{name}")
150     @ApiOperation(value = "Create Keyspace", response = String.class,hidden = true)
151     @Consumes(MediaType.APPLICATION_JSON)
152     @Produces(MediaType.APPLICATION_JSON)
153     public Response createKeySpace(
154                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
155                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
156                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
157                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
158                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
159                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
160                     JsonKeySpace kspObject,
161                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) {
162         try {
163         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
164         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) ");
165         logger.info(EELFLoggerDelegate.applicationLogger,"In Create Keyspace " + keyspaceName);
166         if ( KEYSPACE_ACTIVE ) {
167             logger.info(EELFLoggerDelegate.applicationLogger,"Creating Keyspace " + keyspaceName);
168             Map<String,String> userCredentials = MusicUtil.extractBasicAuthentication(authorization);
169             String userId = userCredentials.get(MusicUtil.USERID);
170             String password = userCredentials.get(MusicUtil.PASSWORD);
171             Map<String, Object> authMap = CachingUtil.verifyOnboarding(ns, userId, password);
172             if (!authMap.isEmpty()) {
173                 logger.error(EELFLoggerDelegate.errorLogger,authMap.get("Exception").toString(), AppMessages.MISSINGDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
174                 response.status(Status.UNAUTHORIZED);
175                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
176             }
177     
178             if (!authenticator.authenticateUser(ns, authorization, keyspaceName, aid, Operation.CREATE_KEYSPACE)) {
179                 return response.status(Status.UNAUTHORIZED)
180                         .entity(new JsonResponse(ResultType.FAILURE)
181                                 .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
182                                 .toMap()).build();
183             }  
184     
185             String consistency = MusicUtil.EVENTUAL;// for now this needs only
186                                                     // eventual consistency
187     
188             if(kspObject == null || kspObject.getReplicationInfo() == null) {
189                 response.status(Status.BAD_REQUEST);
190                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult()).toMap()).build();
191             }
192             PreparedQueryObject queryObject = new PreparedQueryObject();
193             if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && kspObject.getConsistencyInfo().get("consistency") != null) {
194                 if(MusicUtil.isValidConsistency(kspObject.getConsistencyInfo().get("consistency")))
195                     queryObject.setConsistency(kspObject.getConsistencyInfo().get("consistency"));
196                 else
197                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
198             }
199             long start = System.currentTimeMillis();
200             Map<String, Object> replicationInfo = kspObject.getReplicationInfo();
201             String repString = null;
202             try {
203                 repString = "{" + MusicUtil.jsonMaptoSqlString(replicationInfo, ",") + "}";
204             } catch (Exception e) {
205                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
206     
207             }
208             queryObject.appendQueryString(
209                             "CREATE KEYSPACE " + keyspaceName + " WITH replication = " + repString);
210             if (kspObject.getDurabilityOfWrites() != null) {
211                 queryObject.appendQueryString(
212                                 " AND durable_writes = " + kspObject.getDurabilityOfWrites());
213             }
214     
215             queryObject.appendQueryString(";");
216             long end = System.currentTimeMillis();
217             logger.info(EELFLoggerDelegate.applicationLogger,
218                             "Time taken for setting up query in create keyspace:" + (end - start));
219     
220             ResultType result = ResultType.FAILURE;
221             try {
222                 result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
223                 logger.info(EELFLoggerDelegate.applicationLogger, "result = " + result);
224             } catch ( MusicServiceException ex) {
225                 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
226                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("err:" + ex.getMessage()).toMap()).build();
227             }
228     
229             try {
230                 queryObject = new PreparedQueryObject();
231                 queryObject.appendQueryString("CREATE ROLE IF NOT EXISTS '" + userId
232                                 + "' WITH PASSWORD = '" + password + "' AND LOGIN = true;");
233                 MusicCore.nonKeyRelatedPut(queryObject, consistency);
234                 queryObject = new PreparedQueryObject();
235                 queryObject.appendQueryString("GRANT ALL PERMISSIONS on KEYSPACE " + keyspaceName
236                                     + " to '" + userId + "'");
237                 queryObject.appendQueryString(";");
238                 MusicCore.nonKeyRelatedPut(queryObject, consistency);
239             } catch (Exception e) {
240                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
241             }
242     
243             try {
244                 boolean isAAF = Boolean.valueOf(CachingUtil.isAAFApplication(ns));
245                 String hashedpwd = BCrypt.hashpw(password, BCrypt.gensalt());
246                 queryObject = new PreparedQueryObject();
247                 queryObject.appendQueryString(
248                             "INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
249                                             + "password, username, is_aaf) values (?,?,?,?,?,?,?)");
250                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), aid));
251                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspaceName));
252                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), ns));
253                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
254                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), hashedpwd));
255                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
256                 queryObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
257                 CachingUtil.updateMusicCache(keyspaceName, ns);
258                 CachingUtil.updateMusicValidateCache(ns, userId, hashedpwd);
259                 MusicCore.eventualPut(queryObject);
260             } catch (Exception e) {
261                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
262                 return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
263             }
264     
265             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Created").toMap()).build();
266         } else {
267             String vError = "Keyspace Creation no longer supported after versions 3.2.x. Contact DBA to create the keyspace.";
268             logger.info(EELFLoggerDelegate.applicationLogger,vError);
269             logger.error(EELFLoggerDelegate.errorLogger,vError, AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
270             return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(vError).toMap()).build();
271         }
272         } finally {
273             EELFLoggerDelegate.mdcRemove("keyspace");
274         }
275         
276     }
277
278     /**
279      *
280      * @param kspObject
281      * @param keyspaceName
282      * @return
283      * @throws Exception
284      */
285     @DELETE
286     @Path("/{name}")
287     @ApiOperation(value = "Delete Keyspace", response = String.class,hidden=true)
288     @Produces(MediaType.APPLICATION_JSON)
289     public Response dropKeySpace(
290                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
291                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
292                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
293                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
294                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
295                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
296                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) throws Exception {
297         try {
298         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
299         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) ");
300         logger.info(EELFLoggerDelegate.applicationLogger,"In Drop Keyspace " + keyspaceName);
301         if ( KEYSPACE_ACTIVE ) {
302             if (!authenticator.authenticateUser(ns, authorization, keyspaceName, aid, Operation.DROP_KEYSPACE)) {
303                 return response.status(Status.UNAUTHORIZED)
304                         .entity(new JsonResponse(ResultType.FAILURE)
305                                 .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
306                                 .toMap()).build();
307             }  
308     
309             String consistency = MusicUtil.EVENTUAL;// for now this needs only
310                                                     // eventual
311             // consistency
312             String appName = CachingUtil.getAppName(keyspaceName);
313             String uuid = CachingUtil.getUuidFromMusicCache(keyspaceName);
314             PreparedQueryObject pQuery = new PreparedQueryObject();
315             pQuery.appendQueryString(
316                             "select  count(*) as count from admin.keyspace_master where application_name=? allow filtering;");
317             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
318             Row row = MusicCore.get(pQuery).one();
319             long count = row.getLong(0);
320     
321             if (count == 0) {
322                 logger.error(EELFLoggerDelegate.errorLogger,"Keyspace not found. Please make sure keyspace exists.", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
323                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Keyspace not found. Please make sure keyspace exists.").toMap()).build();
324             // Admin Functions:
325             } else if (count == 1) {
326                 pQuery = new PreparedQueryObject();
327                 pQuery.appendQueryString(
328                         "UPDATE admin.keyspace_master SET keyspace_name=? where uuid = ?;");
329                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
330                         MusicUtil.DEFAULTKEYSPACENAME));
331                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
332                 MusicCore.nonKeyRelatedPut(pQuery, consistency);
333             } else {
334                 pQuery = new PreparedQueryObject();
335                 pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
336                 pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
337                 MusicCore.nonKeyRelatedPut(pQuery, consistency);
338             }
339     
340             PreparedQueryObject queryObject = new PreparedQueryObject();
341             queryObject.appendQueryString("DROP KEYSPACE " + keyspaceName + ";");
342             ResultType result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
343             if ( result.equals(ResultType.FAILURE) ) {
344                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Deleteing Keyspace " + keyspaceName).toMap()).build();
345             }
346             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Deleted").toMap()).build();
347         } else {
348             String vError = "Keyspace Droping no longer supported after versions 3.2.x. Contact DBA to drop the keyspace.";
349             logger.info(EELFLoggerDelegate.applicationLogger,vError);
350             logger.error(EELFLoggerDelegate.errorLogger,vError, AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
351             return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(vError).toMap()).build();
352         }
353         } finally {
354             EELFLoggerDelegate.mdcRemove("keyspace");
355         }
356     }
357
358     /**
359      *
360      * @param tableObj
361      * @param version
362      * @param keyspace
363      * @param tablename
364      * @param headers
365      * @return
366      * @throws Exception
367      */
368     @POST
369     @Path("/{keyspace: .*}/tables/{tablename: .*}")
370     @ApiOperation(value = "Create Table", response = String.class)
371     @Consumes(MediaType.APPLICATION_JSON)
372     @Produces(MediaType.APPLICATION_JSON)
373     @ApiResponses(value={
374         @ApiResponse(code= 400, message = "Will return JSON response with message"),
375         @ApiResponse(code= 401, message = "Unautorized User")
376     })
377     public Response createTable(
378                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
379                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
380                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
381                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
382                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
383                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
384                      JsonTable tableObj,
385                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
386                     @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename) throws Exception {
387         try {
388         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
389         if(keyspace == null || keyspace.isEmpty() || tablename == null || tablename.isEmpty()){
390             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
391                     .setError("One or more path parameters are not set, please check and try again."
392                         + "Parameter values: keyspace='" + keyspace + "' tablename='" + tablename + "'")
393                           .toMap()).build();
394         }
395         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
396         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.CREATE_TABLE)) {
397             return response.status(Status.UNAUTHORIZED)
398                     .entity(new JsonResponse(ResultType.FAILURE)
399                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
400                             .toMap()).build();
401         }       
402         
403         String consistency = MusicUtil.EVENTUAL;
404         // for now this needs only eventual consistency
405
406         String primaryKey = null;
407         String partitionKey = tableObj.getPartitionKey();
408         String clusterKey = tableObj.getClusteringKey();
409         String filteringKey = tableObj.getFilteringKey();
410         if(filteringKey != null) {
411             clusterKey = clusterKey + "," + filteringKey;
412         }
413         primaryKey = tableObj.getPrimaryKey(); // get primaryKey if available
414
415         PreparedQueryObject queryObject = new PreparedQueryObject();
416         // first read the information about the table fields
417         Map<String, String> fields = tableObj.getFields();
418         StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
419         int counter = 0;
420         for (Map.Entry<String, String> entry : fields.entrySet()) {
421             if (entry.getKey().equals("PRIMARY KEY")) {
422                 primaryKey = entry.getValue(); // replaces primaryKey
423                 primaryKey = primaryKey.trim();
424             } else {
425                   if (counter == 0 )  fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
426                   else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + "");
427             }
428
429             if (counter != (fields.size() - 1) ) {
430
431                 counter = counter + 1; 
432             } else {
433
434                 if((primaryKey != null) && (partitionKey == null)) {
435                     primaryKey = primaryKey.trim();
436                     int count1 = StringUtils.countMatches(primaryKey, ')');
437                     int count2 = StringUtils.countMatches(primaryKey, '(');
438                     if (count1 != count2) {
439                         return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
440                                 .setError("Create Table Error: primary key '(' and ')' do not match, primary key=" + primaryKey)
441                                 .toMap()).build();
442                     }
443
444                     if ( primaryKey.indexOf('(') == -1  || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) ==  primaryKey.length() ) )
445                     {
446                         if (primaryKey.contains(",") ) {
447                             partitionKey= primaryKey.substring(0,primaryKey.indexOf(','));
448                             partitionKey=partitionKey.replaceAll("[\\(]+","");
449                             clusterKey=primaryKey.substring(primaryKey.indexOf(',')+1);  // make sure index
450                             clusterKey=clusterKey.replaceAll("[)]+", "");
451                         } else {
452                             partitionKey=primaryKey;
453                             partitionKey=partitionKey.replaceAll("[\\)]+","");
454                             partitionKey=partitionKey.replaceAll("[\\(]+","");
455                             clusterKey="";
456                         }
457                     } else {   // not null and has ) before the last char
458                         partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
459                         partitionKey=partitionKey.replaceAll("[\\(]+","");
460                         partitionKey = partitionKey.trim();
461                         clusterKey= primaryKey.substring(primaryKey.indexOf(')'));
462                         clusterKey=clusterKey.replaceAll("[\\(]+","");
463                         clusterKey=clusterKey.replaceAll("[\\)]+","");
464                         clusterKey = clusterKey.trim();
465                         if (clusterKey.indexOf(',') == 0) clusterKey=clusterKey.substring(1);
466                         clusterKey = clusterKey.trim();
467                         if (clusterKey.equals(",") ) clusterKey=""; // print error if needed    ( ... ),)
468                     }
469
470                     if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
471                             && (partitionKey.equalsIgnoreCase(clusterKey) ||
472                                     clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) )
473                     {
474                         logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey + " and primary key=" + primaryKey );
475                         return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
476                                 "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")  of"
477                                         + " primary key=" + primaryKey)
478                                 .toMap()).build();
479
480                     }
481
482                     if (partitionKey.isEmpty() )  primaryKey="";
483                     else  if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey  + ")";
484                     else  primaryKey=" (" + partitionKey + ")," + clusterKey;
485
486
487                     if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
488
489                 } // end of length > 0
490                 else {
491                     if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
492                             && (partitionKey.equalsIgnoreCase(clusterKey) ||
493                                     clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) )
494                     {
495                         logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey);
496                         return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
497                                 "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")")
498                                 .toMap()).build();
499                     }
500
501                     if (partitionKey.isEmpty() )  primaryKey="";
502                     else  if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey  + ")";
503                     else  primaryKey=" (" + partitionKey + ")," + clusterKey;
504
505
506                     if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
507                 }
508                 fieldsString.append(")");
509
510             } // end of last field check
511
512         } // end of for each
513         // information about the name-value style properties
514         Map<String, Object> propertiesMap = tableObj.getProperties();
515         StringBuilder propertiesString = new StringBuilder();
516         if (propertiesMap != null) {
517             counter = 0;
518             for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
519                 Object ot = entry.getValue();
520                 String value = ot + "";
521                 if (ot instanceof String) {
522                     value = "'" + value + "'";
523                 } else if (ot instanceof Map) {
524                     @SuppressWarnings("unchecked")
525                     Map<String, Object> otMap = (Map<String, Object>) ot;
526                     value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
527                 }
528
529                 propertiesString.append(entry.getKey() + "=" + value + "");
530                 if (counter != propertiesMap.size() - 1)
531                     propertiesString.append(" AND ");
532
533                 counter = counter + 1;
534             }
535         }
536
537         String clusteringOrder = tableObj.getClusteringOrder();
538
539         if (clusteringOrder != null && !(clusteringOrder.isEmpty())) {
540             String[] arrayClusterOrder = clusteringOrder.split("[,]+");
541
542             for (int i = 0; i < arrayClusterOrder.length; i++) {
543                 String[] clusterS = arrayClusterOrder[i].trim().split("[ ]+");
544                 if ( (clusterS.length ==2)  && (clusterS[1].equalsIgnoreCase("ASC") || clusterS[1].equalsIgnoreCase("DESC"))) {
545                     continue;
546                 } else {
547                     return response.status(Status.BAD_REQUEST)
548                             .entity(new JsonResponse(ResultType.FAILURE)
549                                     .setError("createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname  order; please correct clusteringOrder:"+ clusteringOrder+".")
550                                     .toMap()).build();
551                 }
552                 // add validation for column names in cluster key
553             }
554
555             if (!(clusterKey.isEmpty())) {
556                 clusteringOrder = "CLUSTERING ORDER BY (" +clusteringOrder +")";
557                 //cjc check if propertiesString.length() >0 instead propertiesMap
558                 if (propertiesMap != null) {
559                     propertiesString.append(" AND  "+ clusteringOrder);
560                 } else {
561                     propertiesString.append(clusteringOrder);
562                 }
563             } else {
564                 logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty ");
565             }
566         } //if non empty
567
568         queryObject.appendQueryString(
569                 "CREATE TABLE " + keyspace + "." + tablename + " " + fieldsString);
570
571
572         if (propertiesString != null &&  propertiesString.length()>0 )
573             queryObject.appendQueryString(" WITH " + propertiesString);
574         queryObject.appendQueryString(";");
575         ResultType result = ResultType.FAILURE;
576         try {
577             result = MusicCore.createTable(keyspace, tablename, queryObject, consistency);
578         } catch (MusicServiceException ex) {
579             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.MUSICSERVICEERROR);
580             response.status(Status.BAD_REQUEST);
581             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
582         }
583         if ( result.equals(ResultType.FAILURE) ) {
584             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Creating Table " + tablename).toMap()).build();
585         }
586         return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("TableName " + tablename.trim() + " Created under keyspace " + keyspace.trim()).toMap()).build();
587         } finally {
588             EELFLoggerDelegate.mdcRemove("keyspace");
589         }
590     }
591
592     /**
593      *
594      * @param keyspace
595      * @param tablename
596      * @param fieldName
597      * @param info
598      * @throws Exception
599      */
600     @POST
601     @Path("/{keyspace: .*}/tables/{tablename: .*}/index/{field: .*}")
602     @ApiOperation(value = "Create Index", response = String.class)
603     @Produces(MediaType.APPLICATION_JSON)
604     public Response createIndex(
605                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
606                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
607                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
608                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
609                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
610                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
611                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
612                     @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename,
613                     @ApiParam(value = "Field Name",required = true) @PathParam("field") String fieldName,
614                     @Context UriInfo info) throws Exception {
615         try {
616         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
617         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty()) || (fieldName == null || fieldName.isEmpty())){
618             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
619                     .setError("one or more path parameters are not set, please check and try again")
620                           .toMap()).build();
621         }
622         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
623         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.CREATE_INDEX)) {
624             return response.status(Status.UNAUTHORIZED)
625                     .entity(new JsonResponse(ResultType.FAILURE)
626                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
627                             .toMap()).build();
628         } 
629
630         MultivaluedMap<String, String> rowParams = info.getQueryParameters();
631         String indexName = "";
632         if (rowParams.getFirst("index_name") != null)
633             indexName = rowParams.getFirst("index_name");
634         PreparedQueryObject query = new PreparedQueryObject();
635         query.appendQueryString("Create index if not exists " + indexName + "  on " + keyspace + "."
636                         + tablename + " (" + fieldName + ");");
637
638         ResultType result = ResultType.FAILURE;
639         try {
640             result = MusicCore.nonKeyRelatedPut(query, "eventual");
641         } catch (MusicServiceException ex) {
642             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
643             response.status(Status.BAD_REQUEST);
644             return response.entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
645         }
646         if ( result.equals(ResultType.SUCCESS) ) {
647             return response.status(Status.OK).entity(new JsonResponse(result).setMessage("Index Created on " + keyspace+"."+tablename+"."+fieldName).toMap()).build();
648         } else {
649             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Unknown Error in create index.").toMap()).build();
650         }
651         } finally {
652             EELFLoggerDelegate.mdcRemove("keyspace");
653         }
654     }
655
656     /**
657      *
658      * @param insObj
659      * @param keyspace
660      * @param tablename
661      * @return
662      * @throws Exception
663      */
664     @POST
665     @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
666     @ApiOperation(value = "Insert Into Table", response = String.class)
667     @Consumes(MediaType.APPLICATION_JSON)
668     @Produces(MediaType.APPLICATION_JSON)
669     public Response insertIntoTable(
670                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
671                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
672                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
673                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
674                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
675                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
676                     JsonInsert insObj,
677                     @ApiParam(value = "Keyspace Name",
678                                     required = true) @PathParam("keyspace") String keyspace,
679                     @ApiParam(value = "Table Name",
680                                     required = true) @PathParam("tablename") String tablename) {
681         try {
682         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
683         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
684             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
685                     .setError("one or more path parameters are not set, please check and try again")
686                           .toMap()).build();
687         }
688         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
689         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.INSERT_INTO_TABLE)) {
690             return response.status(Status.UNAUTHORIZED)
691                     .entity(new JsonResponse(ResultType.FAILURE)
692                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
693                             .toMap()).build();
694         }
695
696         Map<String, Object> valuesMap = insObj.getValues();
697         PreparedQueryObject queryObject = new PreparedQueryObject();
698         TableMetadata tableInfo = null;
699         try {
700             tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
701             if(tableInfo == null) {
702                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Table name doesn't exists. Please check the table name.").toMap()).build();
703             }
704         } catch (MusicServiceException e) {
705             logger.error(EELFLoggerDelegate.errorLogger, e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
706             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
707         }
708         String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
709         StringBuilder fieldsString = new StringBuilder("(vector_ts,");
710         String vectorTs =
711                         String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
712         StringBuilder valueString = new StringBuilder("(" + "?" + ",");
713         queryObject.addValue(vectorTs);
714         int counter = 0;
715         String primaryKey = "";
716         Map<String, byte[]> objectMap = insObj.getObjectMap();
717         for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
718             fieldsString.append("" + entry.getKey());
719             Object valueObj = entry.getValue();
720             if (primaryKeyName.equals(entry.getKey())) {
721                 primaryKey = entry.getValue() + "";
722                 primaryKey = primaryKey.replace("'", "''");
723             }
724             DataType colType = null;
725             try {
726                 colType = tableInfo.getColumn(entry.getKey()).getType();
727             } catch(NullPointerException ex) {
728                 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey(), AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
729                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
730             }
731
732             Object formattedValue = null;
733             try {
734               formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
735             } catch (Exception e) {
736               logger.error(EELFLoggerDelegate.errorLogger,e);
737           }
738             valueString.append("?");
739
740             queryObject.addValue(formattedValue);
741
742             if (counter == valuesMap.size() - 1) {
743                 fieldsString.append(")");
744                 valueString.append(")");
745             } else {
746                 fieldsString.append(",");
747                 valueString.append(",");
748             }
749             counter = counter + 1;
750         }
751
752         //blobs..
753         if(objectMap != null) {
754         for (Map.Entry<String, byte[]> entry : objectMap.entrySet()) {
755             if(counter > 0) {
756                 fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ",");
757                 valueString.replace(valueString.length()-1, valueString.length(), ",");
758             }
759             fieldsString.append("" + entry.getKey());
760             byte[] valueObj = entry.getValue();
761             if (primaryKeyName.equals(entry.getKey())) {
762                 primaryKey = entry.getValue() + "";
763                 primaryKey = primaryKey.replace("'", "''");
764             }
765
766             DataType colType = tableInfo.getColumn(entry.getKey()).getType();
767
768             ByteBuffer formattedValue = null;
769
770             if(colType.toString().toLowerCase().contains("blob"))
771                 formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
772
773             valueString.append("?");
774
775             queryObject.addValue(formattedValue);
776             counter = counter + 1;
777             /*if (counter == valuesMap.size() - 1) {
778                 fieldsString.append(")");
779                 valueString.append(")");
780             } else {*/
781                 fieldsString.append(",");
782                 valueString.append(",");
783             //}
784         } }
785
786         if(primaryKey == null || primaryKey.length() <= 0) {
787             logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
788             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Some required partition key parts are missing: "+primaryKeyName).toMap()).build();
789         }
790
791         fieldsString.replace(fieldsString.length()-1, fieldsString.length(), ")");
792         valueString.replace(valueString.length()-1, valueString.length(), ")");
793
794         queryObject.appendQueryString("INSERT INTO " + keyspace + "." + tablename + " "
795                         + fieldsString + " VALUES " + valueString);
796
797         String ttl = insObj.getTtl();
798         String timestamp = insObj.getTimestamp();
799
800         if ((ttl != null) && (timestamp != null)) {
801             logger.info(EELFLoggerDelegate.applicationLogger, "both there");
802             queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
803             queryObject.addValue(Integer.parseInt(ttl));
804             queryObject.addValue(Long.parseLong(timestamp));
805         }
806
807         if ((ttl != null) && (timestamp == null)) {
808             logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
809             queryObject.appendQueryString(" USING TTL ?");
810             queryObject.addValue(Integer.parseInt(ttl));
811         }
812
813         if ((ttl == null) && (timestamp != null)) {
814             logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
815             queryObject.appendQueryString(" USING TIMESTAMP ?");
816             queryObject.addValue(Long.parseLong(timestamp));
817         }
818
819         queryObject.appendQueryString(";");
820
821         ReturnType result = null;
822         String consistency = insObj.getConsistencyInfo().get("type");
823         if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && insObj.getConsistencyInfo().get("consistency") != null) {
824             if(MusicUtil.isValidConsistency(insObj.getConsistencyInfo().get("consistency")))
825                 queryObject.setConsistency(insObj.getConsistencyInfo().get("consistency"));
826             else
827                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
828         }
829         queryObject.setOperation("insert");
830         try {
831             if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
832                 result = MusicCore.eventualPut(queryObject);
833             } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
834                 String lockId = insObj.getConsistencyInfo().get("lockId");
835                 if(lockId == null) {
836                     logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
837                             + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
838                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
839                             + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
840                 }
841                 result = MusicCore.criticalPut(keyspace, tablename, primaryKey, queryObject, lockId,null);
842             } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
843
844                 result = MusicCore.atomicPut(keyspace, tablename, primaryKey, queryObject, null);
845
846             }
847         } catch (Exception ex) {
848             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
849             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
850         }
851
852         if (result==null) {
853             logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
854             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
855         }else if(result.getResult() == ResultType.FAILURE) {
856             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result.getResult()).setError(result.getMessage()).toMap()).build();
857         }
858         return response.status(Status.OK).entity(new JsonResponse(result.getResult()).setMessage("Insert Successful").toMap()).build();
859         } finally {
860             EELFLoggerDelegate.mdcRemove("keyspace");
861         }
862     }
863
864     /**
865      *
866      * @param insObj
867      * @param keyspace
868      * @param tablename
869      * @param info
870      * @return
871      * @throws MusicServiceException 
872      * @throws MusicQueryException 
873      * @throws Exception
874      */
875     @PUT
876     @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
877     @ApiOperation(value = "Update Table", response = String.class)
878     @Consumes(MediaType.APPLICATION_JSON)
879     @Produces(MediaType.APPLICATION_JSON)
880     public Response updateTable(
881                     @ApiParam(value = "Major Version",
882                                     required = true) @PathParam("version") String version,
883                     @ApiParam(value = "Minor Version",
884                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
885                     @ApiParam(value = "Patch Version",
886                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
887                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
888                     @ApiParam(value = "Application namespace",
889                                     required = true) @HeaderParam(NS) String ns,
890                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
891                     JsonUpdate updateObj,
892                     @ApiParam(value = "Keyspace Name",
893                                     required = true) @PathParam("keyspace") String keyspace,
894                     @ApiParam(value = "Table Name",
895                                     required = true) @PathParam("tablename") String tablename,
896                     @Context UriInfo info) throws MusicQueryException, MusicServiceException {
897         try {
898         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
899         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
900             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
901                     .setError("one or more path parameters are not set, please check and try again")
902                           .toMap()).build();
903         }
904         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
905         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.UPDATE_TABLE)) {
906             return response.status(Status.UNAUTHORIZED)
907                     .entity(new JsonResponse(ResultType.FAILURE)
908                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
909                             .toMap()).build();
910         }
911
912         long startTime = System.currentTimeMillis();
913         String operationId = UUID.randomUUID().toString();// just for infoging
914                                                           // purposes.
915         String consistency = updateObj.getConsistencyInfo().get("type");
916
917         logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
918                         + " update-" + operationId + "-------------------------");
919         // obtain the field value pairs of the update
920
921         PreparedQueryObject queryObject = new PreparedQueryObject();
922         Map<String, Object> valuesMap = updateObj.getValues();
923
924         TableMetadata tableInfo;
925         try {
926             tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
927         } catch (MusicServiceException e) {
928             logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
929               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
930         }
931         if (tableInfo == null) {
932             logger.error(EELFLoggerDelegate.errorLogger,"Table information not found. Please check input for table name= "+tablename, AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
933               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
934                             .setError("Table information not found. Please check input for table name= "
935                                             + keyspace + "." + tablename).toMap()).build();
936         }
937         String vectorTs =
938                         String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
939         StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
940         queryObject.addValue(vectorTs);
941         int counter = 0;
942         for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
943             Object valueObj = entry.getValue();
944             DataType colType = null;
945             try {
946                 colType = tableInfo.getColumn(entry.getKey()).getType();
947             } catch(NullPointerException ex) {
948                 logger.error(EELFLoggerDelegate.errorLogger, ex, "Invalid column name : "+entry.getKey());
949                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
950             }
951             Object valueString = null;
952             try {
953               valueString = MusicUtil.convertToActualDataType(colType, valueObj);
954             } catch (Exception e) {
955               logger.error(EELFLoggerDelegate.errorLogger,e);
956             }
957             fieldValueString.append(entry.getKey() + "= ?");
958             queryObject.addValue(valueString);
959             if (counter != valuesMap.size() - 1)
960                 fieldValueString.append(",");
961             counter = counter + 1;
962         }
963         String ttl = updateObj.getTtl();
964         String timestamp = updateObj.getTimestamp();
965
966         queryObject.appendQueryString("UPDATE " + keyspace + "." + tablename + " ");
967         if ((ttl != null) && (timestamp != null)) {
968
969             logger.info("both there");
970             queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
971             queryObject.addValue(Integer.parseInt(ttl));
972             queryObject.addValue(Long.parseLong(timestamp));
973         }
974
975         if ((ttl != null) && (timestamp == null)) {
976             logger.info("ONLY TTL there");
977             queryObject.appendQueryString(" USING TTL ?");
978             queryObject.addValue(Integer.parseInt(ttl));
979         }
980
981         if ((ttl == null) && (timestamp != null)) {
982             logger.info("ONLY timestamp there");
983             queryObject.appendQueryString(" USING TIMESTAMP ?");
984             queryObject.addValue(Long.parseLong(timestamp));
985         }
986         // get the row specifier
987         RowIdentifier rowId = null;
988         try {
989             rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
990             if(rowId == null || rowId.primarKeyValue.isEmpty()) {
991                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
992                         .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();
993             }
994         } catch (MusicServiceException ex) {
995             logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
996               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
997         }
998
999         queryObject.appendQueryString(
1000                         " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
1001
1002         // get the conditional, if any
1003         Condition conditionInfo;
1004         if (updateObj.getConditions() == null)
1005             conditionInfo = null;
1006         else {// to avoid parsing repeatedly, just send the select query to
1007               // obtain row
1008             PreparedQueryObject selectQuery = new PreparedQueryObject();
1009             selectQuery.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + " WHERE "
1010                             + rowId.rowIdString + ";");
1011             selectQuery.addValue(rowId.primarKeyValue);
1012             conditionInfo = new Condition(updateObj.getConditions(), selectQuery);
1013         }
1014
1015         ReturnType operationResult = null;
1016         long jsonParseCompletionTime = System.currentTimeMillis();
1017
1018         if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && updateObj.getConsistencyInfo().get("consistency") != null) {
1019             if(MusicUtil.isValidConsistency(updateObj.getConsistencyInfo().get("consistency")))
1020                 queryObject.setConsistency(updateObj.getConsistencyInfo().get("consistency"));
1021             else
1022                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
1023         }
1024         queryObject.setOperation("update");
1025         if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
1026             operationResult = MusicCore.eventualPut(queryObject);
1027         else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1028             String lockId = updateObj.getConsistencyInfo().get("lockId");
1029             if(lockId == null) {
1030                 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1031                         + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1032                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1033                         + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1034             }
1035             operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
1036                             queryObject, lockId, conditionInfo);
1037         } else if (consistency.equalsIgnoreCase("atomic_delete_lock")) {
1038             // this function is mainly for the benchmarks
1039             try {
1040               operationResult = MusicCore.atomicPutWithDeleteLock(keyspace, tablename,
1041                               rowId.primarKeyValue, queryObject, conditionInfo);
1042             } catch (MusicLockingException e) {
1043                 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1044                   return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
1045             }
1046         } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1047             try {
1048               operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
1049                               queryObject, conditionInfo);
1050             } catch (MusicLockingException e) {
1051                 logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1052                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
1053             }
1054         }else if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
1055             operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
1056         }
1057         long actualUpdateCompletionTime = System.currentTimeMillis();
1058
1059         long endTime = System.currentTimeMillis();
1060         String timingString = "Time taken in ms for Music " + consistency + " update-" + operationId
1061                         + ":" + "|total operation time:" + (endTime - startTime)
1062                         + "|json parsing time:" + (jsonParseCompletionTime - startTime)
1063                         + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
1064                         + "|";
1065
1066         if (operationResult != null && operationResult.getTimingInfo() != null) {
1067             String lockManagementTime = operationResult.getTimingInfo();
1068             timingString = timingString + lockManagementTime;
1069         }
1070         logger.info(EELFLoggerDelegate.applicationLogger, timingString);
1071
1072         if (operationResult==null) {
1073             logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1074               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
1075         }
1076         if ( operationResult.getResult() == ResultType.SUCCESS ) {
1077             return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
1078         } else {
1079             logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1080             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(operationResult.getResult()).setError(operationResult.getMessage()).toMap()).build();
1081         }
1082         } finally {
1083             EELFLoggerDelegate.mdcRemove("keyspace");
1084         }
1085     }
1086
1087     /**
1088      *
1089      * @param delObj
1090      * @param keyspace
1091      * @param tablename
1092      * @param info
1093      * @return
1094      * @throws MusicServiceException 
1095      * @throws MusicQueryException 
1096      * @throws Exception
1097      */
1098     @DELETE
1099     @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
1100     @ApiOperation(value = "Delete From table", response = String.class)
1101     @Consumes(MediaType.APPLICATION_JSON)
1102     @Produces(MediaType.APPLICATION_JSON)
1103     public Response deleteFromTable(
1104                     @ApiParam(value = "Major Version",
1105                                     required = true) @PathParam("version") String version,
1106                     @ApiParam(value = "Minor Version",
1107                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1108                     @ApiParam(value = "Patch Version",
1109                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1110                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1111                     @ApiParam(value = "Application namespace",
1112                                     required = true) @HeaderParam(NS) String ns,
1113                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1114                     JsonDelete delObj,
1115                     @ApiParam(value = "Keyspace Name",
1116                                     required = true) @PathParam("keyspace") String keyspace,
1117                     @ApiParam(value = "Table Name",
1118                                     required = true) @PathParam("tablename") String tablename,
1119                     @Context UriInfo info) throws MusicQueryException, MusicServiceException {
1120         try {
1121         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1122         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1123             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1124                     .setError("one or more path parameters are not set, please check and try again")
1125                           .toMap()).build();
1126         }
1127         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1128         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.DELETE_FROM_TABLE)) {
1129             return response.status(Status.UNAUTHORIZED)
1130                     .entity(new JsonResponse(ResultType.FAILURE)
1131                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
1132                             .toMap()).build();
1133         }
1134  
1135         if(delObj == null) {
1136             logger.error(EELFLoggerDelegate.errorLogger,"Required HTTP Request body is missing.", AppMessages.MISSINGDATA  ,ErrorSeverity.WARN, ErrorTypes.DATAERROR);
1137               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Required HTTP Request body is missing.").toMap()).build();
1138         }
1139         PreparedQueryObject queryObject = new PreparedQueryObject();
1140         StringBuilder columnString = new StringBuilder();
1141
1142         int counter = 0;
1143         List<String> columnList = delObj.getColumns();
1144         if (columnList != null) {
1145             for (String column : columnList) {
1146                 columnString.append(column);
1147                 if (counter != columnList.size() - 1)
1148                     columnString.append(",");
1149                 counter = counter + 1;
1150             }
1151         }
1152
1153         // get the row specifier
1154         RowIdentifier rowId = null;
1155         try {
1156             rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1157         } catch (MusicServiceException ex) {
1158             logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1159               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1160         }
1161         String rowSpec = rowId.rowIdString.toString();
1162
1163         if ((columnList != null) && (!rowSpec.isEmpty())) {
1164             queryObject.appendQueryString("DELETE " + columnString + " FROM " + keyspace + "."
1165                             + tablename + " WHERE " + rowSpec + ";");
1166         }
1167
1168         if ((columnList == null) && (!rowSpec.isEmpty())) {
1169             queryObject.appendQueryString("DELETE FROM " + keyspace + "." + tablename + " WHERE "
1170                             + rowSpec + ";");
1171         }
1172
1173         if ((columnList != null) && (rowSpec.isEmpty())) {
1174             queryObject.appendQueryString(
1175                             "DELETE " + columnString + " FROM " + keyspace + "." + rowSpec + ";");
1176         }
1177         // get the conditional, if any
1178         Condition conditionInfo;
1179         if (delObj.getConditions() == null)
1180             conditionInfo = null;
1181         else {// to avoid parsing repeatedly, just send the select query to
1182               // obtain row
1183             PreparedQueryObject selectQuery = new PreparedQueryObject();
1184             selectQuery.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + " WHERE "
1185                             + rowId.rowIdString + ";");
1186             selectQuery.addValue(rowId.primarKeyValue);
1187             conditionInfo = new Condition(delObj.getConditions(), selectQuery);
1188         }
1189
1190         String consistency = delObj.getConsistencyInfo().get("type");
1191
1192
1193         if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL) && delObj.getConsistencyInfo().get("consistency")!=null) {
1194
1195             if(MusicUtil.isValidConsistency(delObj.getConsistencyInfo().get("consistency")))
1196                 queryObject.setConsistency(delObj.getConsistencyInfo().get("consistency"));
1197             else
1198                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Invalid Consistency type").toMap()).build();
1199         }
1200
1201         ReturnType operationResult = null;
1202         queryObject.setOperation("delete");
1203         try {
1204             if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
1205                 operationResult = MusicCore.eventualPut(queryObject);
1206             else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1207                 String lockId = delObj.getConsistencyInfo().get("lockId");
1208                 if(lockId == null) {
1209                     logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1210                             + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1211                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1212                             + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1213                 }
1214                 operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
1215                                 queryObject, lockId, conditionInfo);
1216             } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1217                     operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
1218                                     queryObject, conditionInfo);
1219             } else if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
1220                 
1221                 operationResult = MusicCore.eventualPut_nb(queryObject, keyspace, tablename, rowId.primarKeyValue);
1222             }
1223         } catch (MusicLockingException e) {
1224             logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1225               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1226                     .setError("Unable to perform Delete operation. Exception from music").toMap()).build();
1227         }
1228         if (operationResult==null) {
1229             logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1230             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
1231         }
1232         if (operationResult.getResult().equals(ResultType.SUCCESS)) {
1233             return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
1234         } else {
1235             logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1236               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(operationResult.getMessage()).toMap()).build();
1237         }
1238         } finally {
1239             EELFLoggerDelegate.mdcRemove("keyspace");
1240         }
1241     }
1242
1243     /**
1244      *
1245      * @param tabObj
1246      * @param keyspace
1247      * @param tablename
1248      * @throws Exception
1249      */
1250     @DELETE
1251     @Path("/{keyspace: .*}/tables/{tablename: .*}")
1252     @ApiOperation(value = "Drop Table", response = String.class)
1253     @Produces(MediaType.APPLICATION_JSON)
1254     public Response dropTable(
1255                     @ApiParam(value = "Major Version",
1256                                     required = true) @PathParam("version") String version,
1257                     @ApiParam(value = "Minor Version",
1258                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1259                     @ApiParam(value = "Patch Version",
1260                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1261                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1262                     @ApiParam(value = "Application namespace",
1263                                     required = true) @HeaderParam(NS) String ns,
1264                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1265                     @ApiParam(value = "Keyspace Name",
1266                                     required = true) @PathParam("keyspace") String keyspace,
1267                     @ApiParam(value = "Table Name",
1268                                     required = true) @PathParam("tablename") String tablename) throws Exception {
1269         try {
1270         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1271         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1272             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1273                     .setError("one or more path parameters are not set, please check and try again")
1274                           .toMap()).build();
1275         }
1276         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1277         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.DROP_TABLE)) {
1278             return response.status(Status.UNAUTHORIZED)
1279                     .entity(new JsonResponse(ResultType.FAILURE)
1280                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
1281                             .toMap()).build();
1282         }
1283
1284         String consistency = "eventual";// for now this needs only eventual
1285                                         // consistency
1286         PreparedQueryObject query = new PreparedQueryObject();
1287         query.appendQueryString("DROP TABLE  " + keyspace + "." + tablename + ";");
1288         try {
1289             return response.status(Status.OK).entity(new JsonResponse(MusicCore.nonKeyRelatedPut(query, consistency)).toMap()).build();
1290         } catch (MusicServiceException ex) {
1291             logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1292             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1293         }
1294         } finally {
1295             EELFLoggerDelegate.mdcRemove("keyspace");
1296         }
1297     }
1298
1299     /**
1300      *
1301      * @param selObj
1302      * @param keyspace
1303      * @param tablename
1304      * @param info
1305      * @return
1306      */
1307     @PUT
1308     @Path("/{keyspace: .*}/tables/{tablename: .*}/rows/criticalget")
1309     @ApiOperation(value = "Select Critical", response = Map.class)
1310     @Consumes(MediaType.APPLICATION_JSON)
1311     @Produces(MediaType.APPLICATION_JSON)
1312     public Response selectCritical(
1313                     @ApiParam(value = "Major Version",
1314                                     required = true) @PathParam("version") String version,
1315                     @ApiParam(value = "Minor Version",
1316                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1317                     @ApiParam(value = "Patch Version",
1318                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1319                     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1320                     @ApiParam(value = "Application namespace",
1321                                     required = true) @HeaderParam(NS) String ns,
1322                     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1323                     JsonInsert selObj,
1324                     @ApiParam(value = "Keyspace Name",
1325                                     required = true) @PathParam("keyspace") String keyspace,
1326                     @ApiParam(value = "Table Name",
1327                                     required = true) @PathParam("tablename") String tablename,
1328                     @Context UriInfo info) throws Exception {
1329         try {
1330         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1331         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1332             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1333                     .setError("one or more path parameters are not set, please check and try again")
1334                           .toMap()).build();
1335         }
1336         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1337         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.SELECT_CRITICAL)) {
1338             return response.status(Status.UNAUTHORIZED)
1339                     .entity(new JsonResponse(ResultType.FAILURE)
1340                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
1341                             .toMap()).build();
1342         }
1343
1344         String lockId = selObj.getConsistencyInfo().get("lockId");
1345
1346         PreparedQueryObject queryObject = new PreparedQueryObject();
1347
1348         RowIdentifier rowId = null;
1349         try {
1350             rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1351         } catch (MusicServiceException ex) {
1352             logger.error(EELFLoggerDelegate.errorLogger,ex, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1353               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1354         }
1355         queryObject.appendQueryString(
1356                         "SELECT *  FROM " + keyspace + "." + tablename + " WHERE " + rowId.rowIdString + ";");
1357
1358         ResultSet results = null;
1359
1360         String consistency = selObj.getConsistencyInfo().get("type");
1361
1362         if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1363             if(lockId == null) {
1364                 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1365                         + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1366                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1367                         + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1368             }
1369             results = MusicCore.criticalGet(keyspace, tablename, rowId.primarKeyValue, queryObject,
1370                             lockId);
1371         } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1372             results = MusicCore.atomicGet(keyspace, tablename, rowId.primarKeyValue, queryObject);
1373         }
1374         if(results!=null && results.getAvailableWithoutFetching() >0) {
1375             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1376         }
1377         return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setError("No data found").toMap()).build();
1378
1379         } finally {
1380             EELFLoggerDelegate.mdcRemove("keyspace");
1381         }
1382     }
1383
1384     /**
1385      *
1386      * @param keyspace
1387      * @param tablename
1388      * @param info
1389      * @return
1390      * @throws Exception
1391      */
1392     @GET
1393     @Path("/{keyspace: .*}/tables/{tablename: .*}/rows")
1394     @ApiOperation(value = "Select All or Select Specific", response = Map.class)
1395     @Produces(MediaType.APPLICATION_JSON)
1396     public Response select(
1397             @ApiParam(value = "Major Version",
1398                             required = true) @PathParam("version") String version,
1399             @ApiParam(value = "Minor Version",
1400                             required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1401             @ApiParam(value = "Patch Version",
1402                             required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1403             @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
1404             @ApiParam(value = "Application namespace",
1405                             required = true) @HeaderParam(NS) String ns,
1406             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
1407             @ApiParam(value = "Keyspace Name",
1408                             required = true) @PathParam("keyspace") String keyspace,
1409             @ApiParam(value = "Table Name",
1410                             required = true) @PathParam("tablename") String tablename,
1411             @Context UriInfo info) throws Exception {
1412         try { 
1413         ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
1414         if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){
1415             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1416                     .setError("one or more path parameters are not set, please check and try again")
1417                           .toMap()).build();
1418         }
1419         EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) ");
1420         if (!authenticator.authenticateUser(ns, authorization, keyspace, aid, Operation.SELECT)) {
1421             return response.status(Status.UNAUTHORIZED)
1422                     .entity(new JsonResponse(ResultType.FAILURE)
1423                             .setError("Unauthorized: Please check username, password and make sure your app is onboarded")
1424                             .toMap()).build();
1425         }
1426
1427         PreparedQueryObject queryObject = new PreparedQueryObject();
1428
1429         if (info.getQueryParameters().isEmpty())// select all
1430             queryObject.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + ";");
1431         else {
1432             int limit = -1; // do not limit the number of results
1433             try {
1434                 queryObject = selectSpecificQuery(keyspace, tablename, info, limit);
1435             } catch (MusicServiceException ex) {
1436                 logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1437                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1438             }
1439         }
1440
1441         try {
1442             ResultSet results = MusicCore.get(queryObject);
1443             if(results.getAvailableWithoutFetching() >0) {
1444                 return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
1445             }
1446             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).setError("No data found").toMap()).build();
1447         } catch (MusicServiceException ex) {
1448             logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR  ,ErrorSeverity.ERROR, ErrorTypes.MUSICSERVICEERROR);
1449             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1450         }
1451         } finally {
1452             EELFLoggerDelegate.mdcRemove("keyspace");
1453         }
1454     }
1455
1456     /**
1457      *
1458      * @param keyspace
1459      * @param tablename
1460      * @param info
1461      * @param limit
1462      * @return
1463      * @throws MusicServiceException
1464      */
1465     public PreparedQueryObject selectSpecificQuery(String keyspace,
1466             String tablename, UriInfo info, int limit)
1467                     throws MusicServiceException {
1468
1469         PreparedQueryObject queryObject = new PreparedQueryObject();
1470         StringBuilder rowIdString = getRowIdentifier(keyspace, tablename, info.getQueryParameters(),
1471                         queryObject).rowIdString;
1472
1473         queryObject.appendQueryString(
1474                         "SELECT *  FROM " + keyspace + "." + tablename + " WHERE " + rowIdString);
1475
1476         if (limit != -1) {
1477             queryObject.appendQueryString(" LIMIT " + limit);
1478         }
1479
1480         queryObject.appendQueryString(";");
1481         return queryObject;
1482
1483     }
1484
1485     /**
1486      *
1487      * @param keyspace
1488      * @param tablename
1489      * @param rowParams
1490      * @param queryObject
1491      * @return
1492      * @throws MusicServiceException
1493      */
1494     private RowIdentifier getRowIdentifier(String keyspace, String tablename,
1495                     MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
1496                     throws MusicServiceException {
1497         StringBuilder rowSpec = new StringBuilder();
1498         int counter = 0;
1499         TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename);
1500         if (tableInfo == null) {
1501             logger.error(EELFLoggerDelegate.errorLogger,
1502                             "Table information not found. Please check input for table name= "
1503                                             + keyspace + "." + tablename);
1504             throw new MusicServiceException(
1505                             "Table information not found. Please check input for table name= "
1506                                             + keyspace + "." + tablename);
1507         }
1508         StringBuilder primaryKey = new StringBuilder();
1509         for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
1510             String keyName = entry.getKey();
1511             List<String> valueList = entry.getValue();
1512             String indValue = valueList.get(0);
1513             DataType colType = null;
1514             Object formattedValue = null;
1515             try {
1516               colType = tableInfo.getColumn(entry.getKey()).getType();
1517               formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
1518             } catch (Exception e) {
1519               logger.error(EELFLoggerDelegate.errorLogger,e);
1520             }
1521             if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey()))
1522             primaryKey.append(indValue);
1523             rowSpec.append(keyName + "= ?");
1524             queryObject.addValue(formattedValue);
1525             if (counter != rowParams.size() - 1)
1526                 rowSpec.append(" AND ");
1527             counter = counter + 1;
1528         }
1529         return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);
1530     }
1531 }