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