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