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