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