Code Coverage, Auth ID, Docker
[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  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  * 
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  * 
19  * ============LICENSE_END=============================================
20  * ====================================================================
21  */
22 package org.onap.music.rest;
23
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.UUID;
28 import javax.ws.rs.Consumes;
29 import javax.ws.rs.DELETE;
30 import javax.ws.rs.GET;
31 import javax.ws.rs.HeaderParam;
32 import javax.ws.rs.POST;
33 import javax.ws.rs.PUT;
34 import javax.ws.rs.Path;
35 import javax.ws.rs.PathParam;
36 import javax.ws.rs.Produces;
37 import javax.ws.rs.core.Context;
38 import javax.ws.rs.core.HttpHeaders;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.MultivaluedMap;
41 import javax.ws.rs.core.Response;
42 import javax.ws.rs.core.Response.ResponseBuilder;
43 import javax.ws.rs.core.Response.Status;
44 import javax.ws.rs.core.UriInfo;
45 import org.onap.music.datastore.PreparedQueryObject;
46 import org.onap.music.datastore.jsonobjects.JsonDelete;
47 import org.onap.music.datastore.jsonobjects.JsonInsert;
48 import org.onap.music.datastore.jsonobjects.JsonKeySpace;
49 import org.onap.music.datastore.jsonobjects.JsonTable;
50 import org.onap.music.datastore.jsonobjects.JsonUpdate;
51 import org.onap.music.eelf.logging.EELFLoggerDelegate;
52 import org.onap.music.exceptions.MusicLockingException;
53 import org.onap.music.eelf.logging.format.AppMessages;
54 import org.onap.music.eelf.logging.format.ErrorSeverity;
55 import org.onap.music.eelf.logging.format.ErrorTypes;
56 import org.onap.music.exceptions.MusicServiceException;
57 import org.onap.music.main.CachingUtil;
58 import org.onap.music.main.MusicCore;
59 import org.onap.music.main.MusicCore.Condition;
60 import org.onap.music.main.MusicUtil;
61 import org.onap.music.main.ResultType;
62 import org.onap.music.main.ReturnType;
63 import org.onap.music.response.jsonobjects.JsonResponse;
64
65 import com.datastax.driver.core.DataType;
66 import com.datastax.driver.core.ResultSet;
67 import com.datastax.driver.core.Row;
68 import com.datastax.driver.core.TableMetadata;
69 import io.swagger.annotations.Api;
70 import io.swagger.annotations.ApiOperation;
71 import io.swagger.annotations.ApiParam;
72
73 /* Version 2 Class */
74 //@Path("/v{version: [0-9]+}/keyspaces")
75 @Path("/v2/keyspaces")
76 @Api(value = "Data Api")
77 public class RestMusicDataAPI {
78     /*
79      * Header values for Versioning X-minorVersion *** - Used to request or communicate a MINOR
80      * version back from the client to the server, and from the server back to the client - This
81      * will be the MINOR version requested by the client, or the MINOR version of the last MAJOR
82      * version (if not specified by the client on the request) - Contains a single position value
83      * (e.g. if the full version is 1.24.5, X-minorVersion = "24") - Is optional for the client on
84      * request; however, this header should be provided if the client needs to take advantage of
85      * MINOR incremented version functionality - Is mandatory for the server on response
86      * 
87      *** X-patchVersion *** - Used only to communicate a PATCH version in a response for
88      * troubleshooting purposes only, and will not be provided by the client on request - This will
89      * be the latest PATCH version of the MINOR requested by the client, or the latest PATCH version
90      * of the MAJOR (if not specified by the client on the request) - Contains a single position
91      * value (e.g. if the full version is 1.24.5, X-patchVersion = "5") - Is mandatory for the
92      * server on response  (CURRENTLY NOT USED)
93      *
94      *** X-latestVersion *** - Used only to communicate an API's latest version - Is mandatory for the
95      * server on response, and shall include the entire version of the API (e.g. if the full version
96      * is 1.24.5, X-latestVersion = "1.24.5") - Used in the response to inform clients that they are
97      * not using the latest version of the API (CURRENTLY NOT USED)
98      *
99      */
100
101     private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicDataAPI.class);
102     private static final String XLATESTVERSION = "X-latestVersion";
103     private static final String XMINORVERSION = "X-minorVersion";
104     private static final String XPATCHVERSION = "X-patchVersion";
105     private static final String NS = "ns";
106     private static final String USERID = "userId";
107     private static final String PASSWORD = "password";
108     
109     private class RowIdentifier {
110         public String primarKeyValue;
111         public StringBuilder rowIdString;
112         @SuppressWarnings("unused")
113         public PreparedQueryObject queryObject;// the string with all the row
114                                                // identifiers separated by AND
115
116         public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
117                         PreparedQueryObject queryObject) {
118             this.primarKeyValue = primaryKeyValue;
119             this.rowIdString = rowIdString;
120             this.queryObject = queryObject;
121         }
122     }
123
124     @SuppressWarnings("unused")
125     private String buildVersion(String major, String minor, String patch) {
126         if (minor != null) {
127             major += "." + minor;
128             if (patch != null) {
129                 major += "." + patch;
130             }
131         }
132         return major;
133     }
134     
135     /**
136      * Currently this will build a header with X-latestVersion, X-minorVersion and X-pathcVersion
137      * X-latestVerstion will be equal to the latest full version.
138      * X-minorVersion - will be equal to the latest minor version.
139      * X-pathVersion - will be equal to the latest patch version.
140      * Future plans will change this. 
141      * @param response
142      * @param major
143      * @param minor
144      * @param patch
145      * @return
146      */
147     private ResponseBuilder buildVersionResponse(String major, String minor, String patch) {
148         ResponseBuilder response = Response.noContent();
149         String versionIn = buildVersion(major,minor,patch);
150         String version = MusicUtil.getVersion();
151         String[] verArray = version.split("\\.",3);
152         if ( minor != null ) { 
153             response.header(XMINORVERSION,minor);
154         } else {
155             response.header(XMINORVERSION,verArray[1]);
156         } 
157         if ( patch != null ) {
158             response.header(XPATCHVERSION,patch);
159         } else {
160             response.header(XPATCHVERSION,verArray[2]);
161         } 
162         response.header(XLATESTVERSION,version);
163         return response;
164     }
165
166     /**
167      * Create Keyspace REST
168      * 
169      * @param kspObject
170      * @param keyspaceName
171      * @return
172      * @throws Exception
173      */
174     @POST
175     @Path("/{name}")
176     @ApiOperation(value = "Create Keyspace", response = String.class)
177     @Consumes(MediaType.APPLICATION_JSON)
178     @Produces(MediaType.APPLICATION_JSON)
179     //public Map<String, Object> createKeySpace(
180     public Response createKeySpace(
181                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
182                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
183                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
184                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
185                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
186                     @ApiParam(value = "userId",required = true) @HeaderParam(USERID) String userId,
187                     @ApiParam(value = "Password",required = true) @HeaderParam(PASSWORD) String password,
188                     JsonKeySpace kspObject,
189                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) {
190         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
191         
192         Map<String, Object> authMap = CachingUtil.verifyOnboarding(ns, userId, password);
193         if (!authMap.isEmpty()) {
194             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
195             response.status(Status.UNAUTHORIZED);
196             return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
197         }
198         if(kspObject == null || kspObject.getReplicationInfo() == null) {
199             authMap.put(ResultType.EXCEPTION.getResult(), ResultType.BODYMISSING.getResult());
200             response.status(Status.BAD_REQUEST);
201             return response.entity(authMap).build();
202         }
203
204         try {
205             authMap = MusicCore.autheticateUser(ns, userId, password, keyspaceName, aid,
206                             "createKeySpace");
207         } catch (Exception e) {
208             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
209             response.status(Status.BAD_REQUEST);
210             return response.entity(new JsonResponse(ResultType.FAILURE).setError("Unable to authenticate.").toMap()).build();
211         }
212         String newAid = null;
213         if (!authMap.isEmpty()) {
214             if (authMap.containsKey("aid")) {
215                 newAid = (String) authMap.get("aid");
216             } else {
217                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
218                 response.status(Status.UNAUTHORIZED);
219                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
220             }
221         }
222
223         String consistency = MusicUtil.EVENTUAL;// for now this needs only
224                                                 // eventual consistency
225
226         PreparedQueryObject queryObject = new PreparedQueryObject();
227         long start = System.currentTimeMillis();
228         Map<String, Object> replicationInfo = kspObject.getReplicationInfo();
229         String repString = null;
230         try {
231             repString = "{" + MusicUtil.jsonMaptoSqlString(replicationInfo, ",") + "}";
232         } catch (Exception e) {
233             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
234             
235         }
236         queryObject.appendQueryString(
237                         "CREATE KEYSPACE " + keyspaceName + " WITH replication = " + repString);
238         if (kspObject.getDurabilityOfWrites() != null) {
239             queryObject.appendQueryString(
240                             " AND durable_writes = " + kspObject.getDurabilityOfWrites());
241         }
242
243         queryObject.appendQueryString(";");
244         long end = System.currentTimeMillis();
245         logger.info(EELFLoggerDelegate.applicationLogger,
246                         "Time taken for setting up query in create keyspace:" + (end - start));
247
248         ResultType result = ResultType.FAILURE;
249         try {
250             result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
251             logger.info(EELFLoggerDelegate.applicationLogger, "result = " + result);
252         } catch ( MusicServiceException ex) {
253             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
254             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("err:" + ex.getMessage()).toMap()).build();
255         }
256         
257         try {
258             queryObject = new PreparedQueryObject();
259             queryObject.appendQueryString("CREATE ROLE IF NOT EXISTS '" + userId
260                             + "' WITH PASSWORD = '" + password + "' AND LOGIN = true;");
261             MusicCore.nonKeyRelatedPut(queryObject, consistency);
262             queryObject = new PreparedQueryObject();
263             queryObject.appendQueryString("GRANT ALL PERMISSIONS on KEYSPACE " + keyspaceName
264                                 + " to '" + userId + "'");
265             queryObject.appendQueryString(";");
266             MusicCore.nonKeyRelatedPut(queryObject, consistency);
267         } catch (Exception e) {
268             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
269         }
270         
271         try {
272             boolean isAAF = Boolean.valueOf(CachingUtil.isAAFApplication(ns));
273             queryObject = new PreparedQueryObject();
274             queryObject.appendQueryString(
275                         "INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
276                                         + "password, username, is_aaf) values (?,?,?,?,?,?,?)");
277             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), newAid));
278             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspaceName));
279             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), ns));
280             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
281             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), password));
282             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
283             queryObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
284             CachingUtil.updateMusicCache(keyspaceName, ns);
285             CachingUtil.updateMusicValidateCache(ns, userId, password);
286             MusicCore.eventualPut(queryObject);
287         } catch (Exception e) {
288             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
289             return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
290         }
291         
292         return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Created").toMap()).build();
293     }
294
295     /**
296      * 
297      * @param kspObject
298      * @param keyspaceName
299      * @return
300      * @throws Exception
301      */
302     @DELETE
303     @Path("/{name}")
304     @ApiOperation(value = "Delete Keyspace", response = String.class)
305     @Produces(MediaType.APPLICATION_JSON)
306     //public Map<String, Object> dropKeySpace(
307     public Response dropKeySpace(
308                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
309                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
310                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
311                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
312                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
313                     @ApiParam(value = "userId",required = true) @HeaderParam(USERID) String userId,
314                     @ApiParam(value = "Password",required = true) @HeaderParam(PASSWORD) String password,
315                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) throws Exception {
316         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
317
318         Map<String, Object> authMap = MusicCore.autheticateUser(ns, userId, password,keyspaceName, aid, "dropKeySpace");
319         if (authMap.containsKey("aid"))
320             authMap.remove("aid");
321         if (!authMap.isEmpty()) {
322             return response.status(Status.UNAUTHORIZED).entity(authMap).build();
323         }
324
325         String consistency = MusicUtil.EVENTUAL;// for now this needs only
326                                                 // eventual
327         // consistency
328         String appName = CachingUtil.getAppName(keyspaceName);
329         String uuid = CachingUtil.getUuidFromMusicCache(keyspaceName);
330         PreparedQueryObject pQuery = new PreparedQueryObject();
331         pQuery.appendQueryString(
332                         "select  count(*) as count from admin.keyspace_master where application_name=? allow filtering;");
333         pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
334         Row row = MusicCore.get(pQuery).one();
335         long count = row.getLong(0);
336
337         if (count == 0) {
338             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
339             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Keyspace not found. Please make sure keyspace exists.").toMap()).build();
340         // Admin Functions:
341         } else if (count == 1) {
342             pQuery = new PreparedQueryObject();
343             pQuery.appendQueryString(
344                     "UPDATE admin.keyspace_master SET keyspace_name=? where uuid = ?;");
345             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
346                     MusicUtil.DEFAULTKEYSPACENAME));
347             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
348             MusicCore.nonKeyRelatedPut(pQuery, consistency);
349         } else {
350             pQuery = new PreparedQueryObject();
351             pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
352             pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
353             MusicCore.nonKeyRelatedPut(pQuery, consistency);
354         }
355
356         PreparedQueryObject queryObject = new PreparedQueryObject();
357         queryObject.appendQueryString("DROP KEYSPACE " + keyspaceName + ";");
358         ResultType result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
359         if ( result.equals(ResultType.FAILURE) ) {
360             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Deleteing Keyspace " + keyspaceName).toMap()).build();
361         }
362         return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Deleted").toMap()).build();
363     }
364
365     /**
366      * 
367      * @param tableObj
368      * @param version
369      * @param keyspace
370      * @param tablename
371      * @param headers
372      * @return
373      * @throws Exception
374      */
375     @POST
376     @Path("/{keyspace}/tables/{tablename}")
377     @ApiOperation(value = "Create Table", response = String.class)
378     @Consumes(MediaType.APPLICATION_JSON)
379     @Produces(MediaType.APPLICATION_JSON)
380     //public Map<String, Object> createTable(
381     public Response createTable(
382                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
383                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
384                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
385                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
386                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
387                     @ApiParam(value = "userId",required = true) @HeaderParam(USERID) String userId,
388                     @ApiParam(value = "Password",required = true) @HeaderParam(PASSWORD) String password,
389                      JsonTable tableObj,
390                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
391                     @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename) throws Exception {
392         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
393         Map<String, Object> authMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
394                         aid, "createTable");
395         if (authMap.containsKey("aid"))
396             authMap.remove("aid");
397         if (!authMap.isEmpty()) {
398             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
399             return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
400         }
401         String consistency = MusicUtil.EVENTUAL;
402         // for now this needs only eventual consistency
403         PreparedQueryObject queryObject = new PreparedQueryObject();
404         // first read the information about the table fields
405         Map<String, String> fields = tableObj.getFields();
406         StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
407         int counter = 0;
408         String primaryKey;
409         for (Map.Entry<String, String> entry : fields.entrySet()) {
410             
411             if (entry.getKey().equals("PRIMARY KEY")) {
412                 if(! entry.getValue().contains("("))
413                     primaryKey = entry.getValue();
414                 else {
415                     primaryKey = entry.getValue().substring(entry.getValue().indexOf('(') + 1);
416                     primaryKey = primaryKey.substring(0, primaryKey.indexOf(')'));
417                 }
418                 fieldsString.append("" + entry.getKey() + " (" + primaryKey + ")");
419             } else
420                 fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
421             if (counter == fields.size() - 1)
422                 fieldsString.append(")");
423             else
424                 fieldsString.append(",");
425             counter = counter + 1;
426         }
427         // information about the name-value style properties
428         Map<String, Object> propertiesMap = tableObj.getProperties();
429         StringBuilder propertiesString = new StringBuilder();
430         if (propertiesMap != null) {
431             counter = 0;
432             for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
433                 Object ot = entry.getValue();
434                 String value = ot + "";
435                 if (ot instanceof String) {
436                     value = "'" + value + "'";
437                 } else if (ot instanceof Map) {
438                     @SuppressWarnings("unchecked")
439                     Map<String, Object> otMap = (Map<String, Object>) ot;
440                     value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
441                 }
442
443                 propertiesString.append(entry.getKey() + "=" + value + "");
444                 if (counter != propertiesMap.size() - 1)
445                     propertiesString.append(" AND ");
446
447                 counter = counter + 1;
448             }
449         }
450
451         queryObject.appendQueryString(
452                         "CREATE TABLE " + keyspace + "." + tablename + " " + fieldsString);
453
454         if (propertiesMap != null)
455             queryObject.appendQueryString(" WITH " + propertiesString);
456
457         queryObject.appendQueryString(";");
458         ResultType result = ResultType.FAILURE;
459
460         try {
461             result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
462         } catch (MusicServiceException ex) {
463             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.MUSICSERVICEERROR);
464             response.status(Status.BAD_REQUEST);
465             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
466         }
467         if ( result.equals(ResultType.FAILURE) ) {
468             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Creating Table " + tablename).toMap()).build();
469         }
470         return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("TableName " + tablename + " Created under keyspace " + keyspace).toMap()).build();
471     }
472
473     /**
474      * 
475      * @param keyspace
476      * @param tablename
477      * @param fieldName
478      * @param info
479      * @throws Exception
480      */
481     @POST
482     @Path("/{keyspace}/tables/{tablename}/index/{field}")
483     @ApiOperation(value = "Create Index", response = String.class)
484     @Produces(MediaType.APPLICATION_JSON)
485     public Response createIndex(
486                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
487                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
488                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
489                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
490                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
491                     @ApiParam(value = "userId",required = true) @HeaderParam(USERID) String userId,
492                     @ApiParam(value = "Password",required = true) @HeaderParam(PASSWORD) String password,
493                     @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace,
494                     @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename,
495                     @ApiParam(value = "Field Name",required = true) @PathParam("field") String fieldName,
496                     @Context UriInfo info) throws Exception {
497         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
498
499         Map<String, Object> authMap = MusicCore.autheticateUser(ns, userId, password, keyspace,aid, "createIndex");
500         response.header(XLATESTVERSION, MusicUtil.getVersion());
501         if (authMap.containsKey("aid"))
502             authMap.remove("aid");
503         if (!authMap.isEmpty()) {
504             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
505             response.status(Status.UNAUTHORIZED);
506             return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
507         }
508         MultivaluedMap<String, String> rowParams = info.getQueryParameters();
509         String indexName = "";
510         if (rowParams.getFirst("index_name") != null)
511             indexName = rowParams.getFirst("index_name");
512         PreparedQueryObject query = new PreparedQueryObject();
513         query.appendQueryString("Create index " + indexName + " if not exists on " + keyspace + "."
514                         + tablename + " (" + fieldName + ");");
515         
516         ResultType result = ResultType.FAILURE;
517         try {
518             result = MusicCore.nonKeyRelatedPut(query, "eventual");
519         } catch (MusicServiceException ex) {
520             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
521             response.status(Status.BAD_REQUEST);
522             return response.entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
523         }
524         if ( result.equals(ResultType.SUCCESS) ) {
525             return response.entity(new JsonResponse(result).setMessage("Index Created on " + keyspace+"."+tablename+"."+fieldName).toMap()).build();
526         } else {
527             return response.entity(new JsonResponse(result).setError("Unknown Error in create index.").toMap()).build();
528         }
529     }
530
531     /**
532      * 
533      * @param insObj
534      * @param keyspace
535      * @param tablename
536      * @return
537      * @throws Exception
538      */
539     @POST
540     @Path("/{keyspace}/tables/{tablename}/rows")
541     @ApiOperation(value = "Insert Into Table", response = String.class)
542     @Consumes(MediaType.APPLICATION_JSON)
543     @Produces(MediaType.APPLICATION_JSON)
544     public Response insertIntoTable(
545                     @ApiParam(value = "Major Version",required = true) @PathParam("version") String version,
546                     @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
547                     @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
548                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
549                     @ApiParam(value = "Application namespace",required = true) @HeaderParam(NS) String ns,
550                     @ApiParam(value = "userId",required = true) @HeaderParam(USERID) String userId,
551                     @ApiParam(value = "Password",required = true) @HeaderParam(PASSWORD) String password,
552                     JsonInsert insObj,
553                     @ApiParam(value = "Keyspace Name",
554                                     required = true) @PathParam("keyspace") String keyspace,
555                     @ApiParam(value = "Table Name",
556                                     required = true) @PathParam("tablename") String tablename) {
557         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
558
559         Map<String, Object> authMap = null;
560         
561         try {
562             authMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
563                           aid, "insertIntoTable");
564         } catch (Exception e) {
565           logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
566           return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
567         }
568         if (authMap.containsKey("aid"))
569             authMap.remove("aid");
570         if (!authMap.isEmpty()) {
571             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.CRITICAL, ErrorTypes.AUTHENTICATIONERROR);
572             return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
573         }
574
575         Map<String, Object> valuesMap = insObj.getValues();
576         PreparedQueryObject queryObject = new PreparedQueryObject();
577         TableMetadata tableInfo = null;
578         try {
579             tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
580             if(tableInfo == null) {
581                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Table name doesn't exists. Please check the table name.").toMap()).build();
582             }
583         } catch (MusicServiceException e) {
584             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
585             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
586         }
587         String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
588         StringBuilder fieldsString = new StringBuilder("(vector_ts,");
589         String vectorTs =
590                         String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
591         StringBuilder valueString = new StringBuilder("(" + "?" + ",");
592         queryObject.addValue(vectorTs);
593         int counter = 0;
594         String primaryKey = "";
595
596         for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
597             fieldsString.append("" + entry.getKey());
598             Object valueObj = entry.getValue();
599             if (primaryKeyName.equals(entry.getKey())) {
600                 primaryKey = entry.getValue() + "";
601                 primaryKey = primaryKey.replace("'", "''");
602             }
603             DataType colType = null;
604             try {
605                 colType = tableInfo.getColumn(entry.getKey()).getType();
606             } catch(NullPointerException ex) {
607                 logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey(), AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
608                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
609             }
610
611             Object formattedValue = null;
612             try {
613               formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
614             } catch (Exception e) {
615               logger.error(EELFLoggerDelegate.errorLogger,e.getMessage());
616           }
617             valueString.append("?");
618             queryObject.addValue(formattedValue);
619
620             if (counter == valuesMap.size() - 1) {
621                 fieldsString.append(")");
622                 valueString.append(")");
623             } else {
624                 fieldsString.append(",");
625                 valueString.append(",");
626             }
627             counter = counter + 1;
628         }
629         
630         if(primaryKey == null || primaryKey.length() <= 0) {
631             logger.error(EELFLoggerDelegate.errorLogger, "Some required partition key parts are missing: "+primaryKeyName );
632             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.SYNTAXERROR).setError("Some required partition key parts are missing: "+primaryKeyName).toMap()).build();
633         }
634
635         queryObject.appendQueryString("INSERT INTO " + keyspace + "." + tablename + " "
636                         + fieldsString + " VALUES " + valueString);
637
638         String ttl = insObj.getTtl();
639         String timestamp = insObj.getTimestamp();
640
641         if ((ttl != null) && (timestamp != null)) {
642             logger.info(EELFLoggerDelegate.applicationLogger, "both there");
643             queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
644             queryObject.addValue(Integer.parseInt(ttl));
645             queryObject.addValue(Long.parseLong(timestamp));
646         }
647
648         if ((ttl != null) && (timestamp == null)) {
649             logger.info(EELFLoggerDelegate.applicationLogger, "ONLY TTL there");
650             queryObject.appendQueryString(" USING TTL ?");
651             queryObject.addValue(Integer.parseInt(ttl));
652         }
653
654         if ((ttl == null) && (timestamp != null)) {
655             logger.info(EELFLoggerDelegate.applicationLogger, "ONLY timestamp there");
656             queryObject.appendQueryString(" USING TIMESTAMP ?");
657             queryObject.addValue(Long.parseLong(timestamp));
658         }
659
660         queryObject.appendQueryString(";");
661
662         ReturnType result = null;
663         String consistency = insObj.getConsistencyInfo().get("type");
664         try {
665             if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
666                 result = MusicCore.eventualPut(queryObject);
667             } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
668                 String lockId = insObj.getConsistencyInfo().get("lockId");
669                 if(lockId == null) {
670                     logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
671                             + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
672                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
673                             + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
674                 }
675                 result = MusicCore.criticalPut(keyspace, tablename, primaryKey, queryObject, lockId,null);
676             } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
677                 result = MusicCore.atomicPut(keyspace, tablename, primaryKey, queryObject, null);
678
679             }
680             else if (consistency.equalsIgnoreCase(MusicUtil.ATOMICDELETELOCK)) {
681                 result = MusicCore.atomicPutWithDeleteLock(keyspace, tablename, primaryKey, queryObject, null);
682
683             }
684         } catch (Exception ex) {
685             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
686             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
687         }
688         
689         if (result==null) {
690             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR);
691             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
692         }
693         return response.status(Status.OK).entity(new JsonResponse(result.getResult()).setMessage("Insert Successful").toMap()).build();
694     }
695
696     /**
697      * 
698      * @param insObj
699      * @param keyspace
700      * @param tablename
701      * @param info
702      * @return
703      * @throws Exception
704      */
705     @PUT
706     @Path("/{keyspace}/tables/{tablename}/rows")
707     @ApiOperation(value = "Update Table", response = String.class)
708     @Consumes(MediaType.APPLICATION_JSON)
709     @Produces(MediaType.APPLICATION_JSON)
710     public Response updateTable(
711                     @ApiParam(value = "Major Version",
712                                     required = true) @PathParam("version") String version,
713                     @ApiParam(value = "Minor Version",
714                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
715                     @ApiParam(value = "Patch Version",
716                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
717                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
718                     @ApiParam(value = "Application namespace",
719                                     required = true) @HeaderParam(NS) String ns,
720                     @ApiParam(value = "userId",
721                                     required = true) @HeaderParam(USERID) String userId,
722                     @ApiParam(value = "Password",
723                                     required = true) @HeaderParam(PASSWORD) String password,
724                     JsonUpdate updateObj,
725                     @ApiParam(value = "Keyspace Name",
726                                     required = true) @PathParam("keyspace") String keyspace,
727                     @ApiParam(value = "Table Name",
728                                     required = true) @PathParam("tablename") String tablename,
729                     @Context UriInfo info) {
730         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
731
732         Map<String, Object> authMap;
733         try {
734             authMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
735                           aid, "updateTable");
736         } catch (Exception e) {
737               logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
738               return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
739         }
740         if (authMap.containsKey("aid"))
741             authMap.remove("aid");
742         if (!authMap.isEmpty()) {
743             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
744               return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
745         }
746         long startTime = System.currentTimeMillis();
747         String operationId = UUID.randomUUID().toString();// just for infoging
748                                                           // purposes.
749         String consistency = updateObj.getConsistencyInfo().get("type");
750         logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency
751                         + " update-" + operationId + "-------------------------");
752         // obtain the field value pairs of the update
753
754         PreparedQueryObject queryObject = new PreparedQueryObject();
755         Map<String, Object> valuesMap = updateObj.getValues();
756
757         TableMetadata tableInfo;
758         try {
759             tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
760         } catch (MusicServiceException e) {
761             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
762               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
763         }
764         if (tableInfo == null) {
765             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
766               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
767                             .setError("Table information not found. Please check input for table name= "
768                                             + keyspace + "." + tablename).toMap()).build();
769         }
770         String vectorTs =
771                         String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
772         StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
773         queryObject.addValue(vectorTs);
774         int counter = 0;
775         for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
776             Object valueObj = entry.getValue();
777             DataType colType = null;
778             try {
779                 colType = tableInfo.getColumn(entry.getKey()).getType();
780             } catch(NullPointerException ex) {
781                 logger.error(EELFLoggerDelegate.errorLogger, "Invalid column name : "+entry.getKey());
782                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Invalid column name : "+entry.getKey()).toMap()).build();
783             }
784             Object valueString = null;
785             try {
786               valueString = MusicUtil.convertToActualDataType(colType, valueObj);
787             } catch (Exception e) {
788               logger.error(EELFLoggerDelegate.errorLogger,e.getMessage());
789             }
790             fieldValueString.append(entry.getKey() + "= ?");
791             queryObject.addValue(valueString);
792             if (counter != valuesMap.size() - 1)
793                 fieldValueString.append(",");
794             counter = counter + 1;
795         }
796         String ttl = updateObj.getTtl();
797         String timestamp = updateObj.getTimestamp();
798
799         queryObject.appendQueryString("UPDATE " + keyspace + "." + tablename + " ");
800         if ((ttl != null) && (timestamp != null)) {
801
802             logger.info("both there");
803             queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
804             queryObject.addValue(Integer.parseInt(ttl));
805             queryObject.addValue(Long.parseLong(timestamp));
806         }
807
808         if ((ttl != null) && (timestamp == null)) {
809             logger.info("ONLY TTL there");
810             queryObject.appendQueryString(" USING TTL ?");
811             queryObject.addValue(Integer.parseInt(ttl));
812         }
813
814         if ((ttl == null) && (timestamp != null)) {
815             logger.info("ONLY timestamp there");
816             queryObject.appendQueryString(" USING TIMESTAMP ?");
817             queryObject.addValue(Long.parseLong(timestamp));
818         }
819         // get the row specifier
820         RowIdentifier rowId = null;
821         try {
822             rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
823             if(rowId == null || rowId.primarKeyValue.isEmpty()) {
824                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
825                         .setError("Mandatory WHERE clause is missing. Please check the input request.").toMap()).build();
826             }
827         } catch (MusicServiceException ex) {
828             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
829               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
830         }
831
832         queryObject.appendQueryString(
833                         " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
834
835         // get the conditional, if any
836         Condition conditionInfo;
837         if (updateObj.getConditions() == null)
838             conditionInfo = null;
839         else {// to avoid parsing repeatedly, just send the select query to
840               // obtain row
841             PreparedQueryObject selectQuery = new PreparedQueryObject();
842             selectQuery.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + " WHERE "
843                             + rowId.rowIdString + ";");
844             selectQuery.addValue(rowId.primarKeyValue);
845             conditionInfo = new MusicCore.Condition(updateObj.getConditions(), selectQuery);
846         }
847
848         ReturnType operationResult = null;
849         long jsonParseCompletionTime = System.currentTimeMillis();
850
851         if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
852             operationResult = MusicCore.eventualPut(queryObject);
853         else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
854             String lockId = updateObj.getConsistencyInfo().get("lockId");
855             if(lockId == null) {
856                 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
857                         + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
858                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
859                         + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
860             }
861             operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
862                             queryObject, lockId, conditionInfo);
863         } else if (consistency.equalsIgnoreCase("atomic_delete_lock")) {
864             // this function is mainly for the benchmarks
865             try {
866               operationResult = MusicCore.atomicPutWithDeleteLock(keyspace, tablename,
867                               rowId.primarKeyValue, queryObject, conditionInfo);
868             } catch (MusicLockingException e) {
869                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
870                   return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
871             }
872         } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
873             try {
874               operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
875                               queryObject, conditionInfo);
876             } catch (MusicLockingException e) {
877                 logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
878                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
879             }
880         }
881         long actualUpdateCompletionTime = System.currentTimeMillis();
882
883         long endTime = System.currentTimeMillis();
884         String timingString = "Time taken in ms for Music " + consistency + " update-" + operationId
885                         + ":" + "|total operation time:" + (endTime - startTime)
886                         + "|json parsing time:" + (jsonParseCompletionTime - startTime)
887                         + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
888                         + "|";
889
890         if (operationResult != null && operationResult.getTimingInfo() != null) {
891             String lockManagementTime = operationResult.getTimingInfo();
892             timingString = timingString + lockManagementTime;
893         }
894         logger.info(EELFLoggerDelegate.applicationLogger, timingString);
895         
896         if (operationResult==null) {
897             logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
898               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
899         }
900         if ( operationResult.getResult() == ResultType.SUCCESS ) {
901             return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
902         } else {
903             logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
904             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(operationResult.getResult()).setError(operationResult.getMessage()).toMap()).build();
905         }
906         
907     }
908
909     /**
910      * 
911      * @param delObj
912      * @param keyspace
913      * @param tablename
914      * @param info
915      * @return
916      * @throws Exception
917      */
918     @DELETE
919     @Path("/{keyspace}/tables/{tablename}/rows")
920     @ApiOperation(value = "Delete From table", response = String.class)
921     @Consumes(MediaType.APPLICATION_JSON)
922     @Produces(MediaType.APPLICATION_JSON)
923     public Response deleteFromTable(
924                     @ApiParam(value = "Major Version",
925                                     required = true) @PathParam("version") String version,
926                     @ApiParam(value = "Minor Version",
927                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
928                     @ApiParam(value = "Patch Version",
929                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
930                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
931                     @ApiParam(value = "Application namespace",
932                                     required = true) @HeaderParam(NS) String ns,
933                     @ApiParam(value = "userId",
934                                     required = true) @HeaderParam(USERID) String userId,
935                     @ApiParam(value = "Password",
936                                     required = true) @HeaderParam(PASSWORD) String password,
937                     JsonDelete delObj,
938                     @ApiParam(value = "Keyspace Name",
939                                     required = true) @PathParam("keyspace") String keyspace,
940                     @ApiParam(value = "Table Name",
941                                     required = true) @PathParam("tablename") String tablename,
942                     @Context UriInfo info) {
943         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
944
945         Map<String, Object> authMap = null;
946         try {
947             authMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
948                             aid, "deleteFromTable");
949         } catch (Exception e) {
950             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
951             return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
952         }
953         if (authMap.containsKey("aid"))
954             authMap.remove("aid");
955         if (!authMap.isEmpty()) {
956             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
957               return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
958         }
959         if(delObj == null) {
960             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGDATA  ,ErrorSeverity.WARN, ErrorTypes.DATAERROR);
961               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Required HTTP Request body is missing.").toMap()).build();
962         }
963         PreparedQueryObject queryObject = new PreparedQueryObject();
964         StringBuilder columnString = new StringBuilder();
965
966         int counter = 0;
967         ArrayList<String> columnList = delObj.getColumns();
968         if (columnList != null) {
969             for (String column : columnList) {
970                 columnString.append(column);
971                 if (counter != columnList.size() - 1)
972                     columnString.append(",");
973                 counter = counter + 1;
974             }
975         }
976
977         // get the row specifier
978         RowIdentifier rowId = null;
979         try {
980             rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
981         } catch (MusicServiceException ex) {
982             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
983               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
984         }
985         String rowSpec = rowId.rowIdString.toString();
986
987         if ((columnList != null) && (!rowSpec.isEmpty())) {
988             queryObject.appendQueryString("DELETE " + columnString + " FROM " + keyspace + "."
989                             + tablename + " WHERE " + rowSpec + ";");
990         }
991
992         if ((columnList == null) && (!rowSpec.isEmpty())) {
993             queryObject.appendQueryString("DELETE FROM " + keyspace + "." + tablename + " WHERE "
994                             + rowSpec + ";");
995         }
996
997         if ((columnList != null) && (rowSpec.isEmpty())) {
998             queryObject.appendQueryString(
999                             "DELETE " + columnString + " FROM " + keyspace + "." + rowSpec + ";");
1000         }
1001         // get the conditional, if any
1002         Condition conditionInfo;
1003         if (delObj.getConditions() == null)
1004             conditionInfo = null;
1005         else {// to avoid parsing repeatedly, just send the select query to
1006               // obtain row
1007             PreparedQueryObject selectQuery = new PreparedQueryObject();
1008             selectQuery.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + " WHERE "
1009                             + rowId.rowIdString + ";");
1010             selectQuery.addValue(rowId.primarKeyValue);
1011             conditionInfo = new MusicCore.Condition(delObj.getConditions(), selectQuery);
1012         }
1013
1014         String consistency = delObj.getConsistencyInfo().get("type");
1015
1016         ReturnType operationResult = null;
1017         try {
1018             if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
1019                 operationResult = MusicCore.eventualPut(queryObject);
1020             else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1021                 String lockId = delObj.getConsistencyInfo().get("lockId");
1022                 if(lockId == null) {
1023                     logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1024                             + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1025                     return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1026                             + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1027                 }
1028                 operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
1029                                 queryObject, lockId, conditionInfo);
1030             } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1031                     operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
1032                                     queryObject, conditionInfo);
1033             }
1034             else if (consistency.equalsIgnoreCase(MusicUtil.ATOMICDELETELOCK)) {
1035                     operationResult = MusicCore.atomicPutWithDeleteLock(keyspace, tablename, rowId.primarKeyValue,
1036                                     queryObject, conditionInfo);
1037             }
1038         } catch (MusicLockingException e) {
1039             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1040               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
1041                     .setError("Unable to perform Delete operation. Exception from music").toMap()).build();
1042         }
1043         if (operationResult==null) {
1044             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1045             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build();
1046         }
1047         if (operationResult.getResult().equals(ResultType.SUCCESS)) {
1048             return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build();
1049         } else {
1050             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1051               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(operationResult.getMessage()).toMap()).build();
1052         }
1053     }
1054
1055     /**
1056      * 
1057      * @param tabObj
1058      * @param keyspace
1059      * @param tablename
1060      * @throws Exception
1061      */
1062     @DELETE
1063     @Path("/{keyspace}/tables/{tablename}")
1064     @ApiOperation(value = "Drop Table", response = String.class)
1065     @Produces(MediaType.APPLICATION_JSON)
1066     public Response dropTable(
1067                     @ApiParam(value = "Major Version",
1068                                     required = true) @PathParam("version") String version,
1069                     @ApiParam(value = "Minor Version",
1070                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1071                     @ApiParam(value = "Patch Version",
1072                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1073                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
1074                     @ApiParam(value = "Application namespace",
1075                                     required = true) @HeaderParam(NS) String ns,
1076                     @ApiParam(value = "userId",
1077                                     required = true) @HeaderParam(USERID) String userId,
1078                     @ApiParam(value = "Password",
1079                                     required = true) @HeaderParam(PASSWORD) String password,
1080                     @ApiParam(value = "Keyspace Name",
1081                                     required = true) @PathParam("keyspace") String keyspace,
1082                     @ApiParam(value = "Table Name",
1083                                     required = true) @PathParam("tablename") String tablename) throws Exception {
1084         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
1085
1086         Map<String, Object> authMap =
1087                         MusicCore.autheticateUser(ns, userId, password, keyspace, aid, "dropTable");
1088         if (authMap.containsKey("aid"))
1089             authMap.remove("aid");
1090         if (!authMap.isEmpty()) {
1091             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
1092             return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
1093         }
1094         String consistency = "eventual";// for now this needs only eventual
1095                                         // consistency
1096         PreparedQueryObject query = new PreparedQueryObject();
1097         query.appendQueryString("DROP TABLE  " + keyspace + "." + tablename + ";");
1098         try {
1099             return response.status(Status.OK).entity(new JsonResponse(MusicCore.nonKeyRelatedPut(query, consistency)).toMap()).build();
1100         } catch (MusicServiceException ex) {
1101             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1102             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1103         }
1104
1105     }
1106
1107     /**
1108      * 
1109      * @param selObj
1110      * @param keyspace
1111      * @param tablename
1112      * @param info
1113      * @return
1114      */
1115     @PUT
1116     @Path("/{keyspace}/tables/{tablename}/rows/criticalget")
1117     @ApiOperation(value = "Select Critical", response = Map.class)
1118     @Consumes(MediaType.APPLICATION_JSON)
1119     @Produces(MediaType.APPLICATION_JSON)
1120     public Response selectCritical(
1121                     @ApiParam(value = "Major Version",
1122                                     required = true) @PathParam("version") String version,
1123                     @ApiParam(value = "Minor Version",
1124                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1125                     @ApiParam(value = "Patch Version",
1126                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1127                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
1128                     @ApiParam(value = "Application namespace",
1129                                     required = true) @HeaderParam(NS) String ns,
1130                     @ApiParam(value = "userId",
1131                                     required = true) @HeaderParam(USERID) String userId,
1132                     @ApiParam(value = "Password",
1133                                     required = true) @HeaderParam(PASSWORD) String password,
1134                     JsonInsert selObj,
1135                     @ApiParam(value = "Keyspace Name",
1136                                     required = true) @PathParam("keyspace") String keyspace,
1137                     @ApiParam(value = "Table Name",
1138                                     required = true) @PathParam("tablename") String tablename,
1139                     @Context UriInfo info) throws Exception {
1140         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
1141
1142         Map<String, Object> authMap = MusicCore.autheticateUser(ns, userId, password, keyspace,aid, "selectCritical");
1143         if (authMap.containsKey("aid"))
1144             authMap.remove("aid");
1145         if (!authMap.isEmpty()) {
1146             logger.error(EELFLoggerDelegate.errorLogger,"Error while authentication... ", AppMessages.MISSINGINFO  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
1147               return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
1148         }
1149         String lockId = selObj.getConsistencyInfo().get("lockId");
1150
1151         PreparedQueryObject queryObject = new PreparedQueryObject();
1152
1153         RowIdentifier rowId = null;
1154         try {
1155             rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(), queryObject);
1156         } catch (MusicServiceException ex) {
1157             logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1158               return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1159         }
1160         queryObject.appendQueryString(
1161                         "SELECT *  FROM " + keyspace + "." + tablename + " WHERE " + rowId.rowIdString + ";");
1162
1163         ResultSet results = null;
1164
1165         String consistency = selObj.getConsistencyInfo().get("type");
1166
1167         if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
1168             if(lockId == null) {
1169                 logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
1170                         + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
1171                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock "
1172                         + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build();
1173             }
1174             results = MusicCore.criticalGet(keyspace, tablename, rowId.primarKeyValue, queryObject,
1175                             lockId);
1176         } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
1177             results = MusicCore.atomicGet(keyspace, tablename, rowId.primarKeyValue, queryObject);
1178         }
1179         
1180         else if (consistency.equalsIgnoreCase(MusicUtil.ATOMICDELETELOCK)) {
1181             results = MusicCore.atomicGetWithDeleteLock(keyspace, tablename, rowId.primarKeyValue, queryObject);
1182         }
1183
1184         return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicCore.marshallResults(results)).toMap()).build();
1185     }
1186
1187     /**
1188      * 
1189      * @param keyspace
1190      * @param tablename
1191      * @param info
1192      * @return
1193      * @throws Exception
1194      */
1195     @GET
1196     @Path("/{keyspace}/tables/{tablename}/rows")
1197     @ApiOperation(value = "Select All or Select Specific", response = Map.class)
1198     @Produces(MediaType.APPLICATION_JSON)
1199     public Response select(
1200                     @ApiParam(value = "Major Version",
1201                                     required = true) @PathParam("version") String version,
1202                     @ApiParam(value = "Minor Version",
1203                                     required = false) @HeaderParam(XMINORVERSION) String minorVersion,
1204                     @ApiParam(value = "Patch Version",
1205                                     required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
1206                     @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
1207                     @ApiParam(value = "Application namespace",
1208                                     required = true) @HeaderParam(NS) String ns,
1209                     @ApiParam(value = "userId",
1210                                     required = true) @HeaderParam(USERID) String userId,
1211                     @ApiParam(value = "Password",
1212                                     required = true) @HeaderParam(PASSWORD) String password,
1213                     @ApiParam(value = "Keyspace Name",
1214                                     required = true) @PathParam("keyspace") String keyspace,
1215                     @ApiParam(value = "Table Name",
1216                                     required = true) @PathParam("tablename") String tablename,
1217                     @Context UriInfo info) throws Exception {
1218         ResponseBuilder response = buildVersionResponse(version, minorVersion, patchVersion);
1219
1220         Map<String, Object> authMap =
1221                         MusicCore.autheticateUser(ns, userId, password, keyspace, aid, "select");
1222         if (authMap.containsKey("aid"))
1223             authMap.remove("aid");
1224         if (!authMap.isEmpty()) {
1225             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.AUTHENTICATIONERROR  ,ErrorSeverity.WARN, ErrorTypes.AUTHENTICATIONERROR);
1226             return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(authMap.get("Exception"))).toMap()).build();
1227         }
1228         PreparedQueryObject queryObject = new PreparedQueryObject();
1229
1230         if (info.getQueryParameters().isEmpty())// select all
1231             queryObject.appendQueryString("SELECT *  FROM " + keyspace + "." + tablename + ";");
1232         else {
1233             int limit = -1; // do not limit the number of results
1234             try {
1235                 queryObject = selectSpecificQuery(version, minorVersion, patchVersion, aid, ns,
1236                                 userId, password, keyspace, tablename, info, limit);
1237             } catch (MusicServiceException ex) {
1238                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
1239                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1240             }
1241         }
1242
1243         try {
1244             ResultSet results = MusicCore.get(queryObject);
1245             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicCore.marshallResults(results)).toMap()).build();
1246         } catch (MusicServiceException ex) {
1247             logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR  ,ErrorSeverity.ERROR, ErrorTypes.MUSICSERVICEERROR);
1248             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build();
1249         }
1250
1251     }
1252
1253     /**
1254      * 
1255      * @param keyspace
1256      * @param tablename
1257      * @param info
1258      * @param limit
1259      * @return
1260      * @throws MusicServiceException
1261      */
1262     public PreparedQueryObject selectSpecificQuery(String version, String minorVersion,
1263                     String patchVersion, String aid, String ns, String userId, String password,
1264                     String keyspace, String tablename, UriInfo info, int limit)
1265                     throws MusicServiceException {
1266
1267         PreparedQueryObject queryObject = new PreparedQueryObject();
1268         StringBuilder rowIdString = getRowIdentifier(keyspace, tablename, info.getQueryParameters(),
1269                         queryObject).rowIdString;
1270
1271         queryObject.appendQueryString(
1272                         "SELECT *  FROM " + keyspace + "." + tablename + " WHERE " + rowIdString);
1273
1274         if (limit != -1) {
1275             queryObject.appendQueryString(" LIMIT " + limit);
1276         }
1277
1278         queryObject.appendQueryString(";");
1279         return queryObject;
1280
1281     }
1282
1283     /**
1284      * 
1285      * @param keyspace
1286      * @param tablename
1287      * @param rowParams
1288      * @param queryObject
1289      * @return
1290      * @throws MusicServiceException
1291      */
1292     private RowIdentifier getRowIdentifier(String keyspace, String tablename,
1293                     MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject)
1294                     throws MusicServiceException {
1295         StringBuilder rowSpec = new StringBuilder();
1296         int counter = 0;
1297         TableMetadata tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
1298         if (tableInfo == null) {
1299             logger.error(EELFLoggerDelegate.errorLogger,
1300                             "Table information not found. Please check input for table name= "
1301                                             + keyspace + "." + tablename);
1302             throw new MusicServiceException(
1303                             "Table information not found. Please check input for table name= "
1304                                             + keyspace + "." + tablename);
1305         }
1306         StringBuilder primaryKey = new StringBuilder();
1307         for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
1308             String keyName = entry.getKey();
1309             List<String> valueList = entry.getValue();
1310             String indValue = valueList.get(0);
1311             DataType colType = null;
1312             Object formattedValue = null;
1313             try {
1314               colType = tableInfo.getColumn(entry.getKey()).getType();
1315               formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
1316             } catch (Exception e) {
1317               logger.error(EELFLoggerDelegate.errorLogger,e.getMessage());
1318             }
1319             primaryKey.append(indValue);
1320             rowSpec.append(keyName + "= ?");
1321             queryObject.addValue(formattedValue);
1322             if (counter != rowParams.size() - 1)
1323                 rowSpec.append(" AND ");
1324             counter = counter + 1;
1325         }
1326         return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);
1327     }
1328 }