Read lock promotion
[music.git] / src / main / java / org / onap / music / rest / RestMusicLocksAPI.java
1 /*
2  * ============LICENSE_START==========================================
3  * org.onap.music
4  * ===================================================================
5  *  Copyright (c) 2017 AT&T Intellectual Property
6  * ===================================================================
7  *  *  Modifications Copyright (c) 2019 Samsung
8  * ===================================================================
9  * 
10  *  Licensed under the Apache License, Version 2.0 (the "License");
11  *  you may not use this file except in compliance with the License.
12  *  You may obtain a copy of the License at
13  * 
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  * 
16  *  Unless required by applicable law or agreed to in writing, software
17  *  distributed under the License is distributed on an "AS IS" BASIS,
18  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  *  See the License for the specific language governing permissions and
20  *  limitations under the License.
21  * 
22  * ============LICENSE_END=============================================
23  * ====================================================================
24  */
25
26 package org.onap.music.rest;
27
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DELETE;
33 import javax.ws.rs.GET;
34 import javax.ws.rs.HeaderParam;
35 import javax.ws.rs.POST;
36 import javax.ws.rs.Path;
37 import javax.ws.rs.PathParam;
38 import javax.ws.rs.Produces;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.Response;
41 import javax.ws.rs.core.Response.ResponseBuilder;
42 import javax.ws.rs.core.Response.Status;
43
44 import org.onap.music.datastore.jsonobjects.JsonLeasedLock;
45 import org.onap.music.datastore.jsonobjects.JsonLock;
46 import org.onap.music.eelf.logging.EELFLoggerDelegate;
47 import org.onap.music.eelf.logging.format.AppMessages;
48 import org.onap.music.eelf.logging.format.ErrorSeverity;
49 import org.onap.music.eelf.logging.format.ErrorTypes;
50 import org.onap.music.exceptions.MusicLockingException;
51 import org.onap.music.lockingservice.cassandra.LockType;
52 import org.onap.music.lockingservice.cassandra.MusicLockState;
53 import org.onap.music.main.MusicCore;
54 import org.onap.music.main.MusicUtil;
55 import org.onap.music.main.ResultType;
56 import org.onap.music.main.ReturnType;
57 import org.onap.music.response.jsonobjects.JsonResponse;
58
59 import io.swagger.annotations.Api;
60 import io.swagger.annotations.ApiOperation;
61 import io.swagger.annotations.ApiParam;
62 import io.swagger.annotations.ApiResponse;
63 import io.swagger.annotations.ApiResponses;
64 import io.swagger.annotations.Example;
65 import io.swagger.annotations.ExampleProperty;
66
67
68 @Path("/v2/locks/")
69 @Api(value="Locking Api")
70 public class RestMusicLocksAPI {
71
72     private EELFLoggerDelegate logger =EELFLoggerDelegate.getLogger(RestMusicLocksAPI.class);
73     private static final String XMINORVERSION = "X-minorVersion";
74     private static final String XPATCHVERSION = "X-patchVersion";
75     private static final String VERSION = "v2";
76
77     /**
78      * Puts the requesting process in the q for this lock. The corresponding
79      * node will be created if it did not already exist
80      * 
81      * @param lockName
82      * @return
83      * @throws Exception 
84      */
85     @POST
86     @Path("/create/{lockname}")
87     @ApiOperation(value = "Create and Acquire a Lock Id for a single row.",
88         notes = "Creates and Acquires a Lock Id for a specific Row in a table based on the key of that row.\n"
89         + " The corresponding lock will be created if it did not already exist."
90         + " Lock Name also the Lock is in the form of keyspaceName.tableName.rowId.\n"
91         + " The Response will be in the form of \"$kesypaceName.tableName.rowId$lockRef\" "
92         + " where the lockRef is a integer representing the Lock Name buffered by \"$\" " 
93         + " followed by the lock number. This term for "
94         + " this response is a lockId and it will be used in other /locks API calls where a "
95         + " lockId is required. If just a lock is required then the form that would be "
96         + " the original lockname(without the buffered \"$\").",
97         response = Map.class)
98     @Consumes(MediaType.APPLICATION_JSON)
99     @Produces(MediaType.APPLICATION_JSON)
100     @ApiResponses(value={
101         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
102             @ExampleProperty(mediaType="application/json",value = 
103                 "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"},"
104                 + "\"status\" : \"SUCCESS\"}")
105         })),
106         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
107             @ExampleProperty(mediaType="application/json",value = 
108                 "{\"error\" : \"Unable to aquire lock\","
109                 + "\"status\" : \"FAILURE\"}") 
110         }))
111     })  
112     public Response createLockReference(
113             @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
114             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
115             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
116             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
117             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
118             JsonLock lockObject,
119             @ApiParam(value = "Lock Owner", required = false) @HeaderParam("owner") String owner,
120             @ApiParam(value = "Application namespace",
121                             required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{
122         try {
123             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
124             Map<String, Object> resultMap = MusicCore.validateLock(lockName);
125             if (resultMap.containsKey("Error")) {
126                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
127                 response.status(Status.BAD_REQUEST);
128                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
129             }
130             String keyspaceName = (String) resultMap.get("keyspace");
131             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
132             
133             //default lock type is write, as this is always semantically safe
134             LockType locktype = LockType.WRITE;
135             if (lockObject!=null && lockObject.getLocktype()!=null) {
136                 locktype = lockObject.getLocktype();
137             }
138             String lockId;
139             try {
140                 lockId= MusicCore.createLockReference(lockName, locktype, owner);
141             } catch (MusicLockingException e) {
142                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
143             }
144             
145             if (lockId == null) {  
146                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.LOCKINGERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
147                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Lock Id is null").toMap()).build();
148             }
149             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setLock(lockId).toMap()).build();
150         } finally {
151             EELFLoggerDelegate.mdcRemove("keyspace");
152         }
153     }
154
155     /**
156      * 
157      * Checks if the node is in the top of the queue and hence acquires the lock
158      * 
159      * @param lockId
160      * @return
161      * @throws Exception 
162      */
163     @GET
164     @Path("/acquire/{lockId}")
165     @ApiOperation(value = "Aquire Lock Id ", 
166         notes = "Checks if the node is in the top of the queue and hence acquires the lock",
167         response = Map.class)
168     @Produces(MediaType.APPLICATION_JSON)    
169     @ApiResponses(value={
170         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
171             @ExampleProperty(mediaType="application/json",value = 
172                 "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"},"
173                 + "\"message\" : \"<integer> is the lock holder for the key\","
174                 + "\"status\" : \"SUCCESS\"}") 
175         })),
176         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
177             @ExampleProperty(mediaType="application/json",value = 
178                 "{\"error\" : \"Unable to aquire lock\","
179                 + "\"status\" : \"FAILURE\"}") 
180         }))
181     })  
182     public Response accquireLock(
183             @ApiParam(value="Lock Id",required=true) @PathParam("lockId") String lockId,
184             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
185             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
186             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
187             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
188             @ApiParam(value = "Application namespace",
189                             required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{
190         try { 
191             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
192             Map<String, Object> resultMap = MusicCore.validateLock(lockId);
193             if (resultMap.containsKey("Error")) {
194                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
195                 response.status(Status.BAD_REQUEST);
196                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
197             }
198             
199             String keyspaceName = (String) resultMap.get("keyspace");
200             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
201             try {
202                 String lockName = lockId.substring(lockId.indexOf('$')+1, lockId.lastIndexOf('$'));
203                 ReturnType lockStatus = MusicCore.acquireLock(lockName,lockId);
204                 if ( lockStatus.getResult().equals(ResultType.SUCCESS)) {
205                     response.status(Status.OK);
206                 } else {
207                     response.status(Status.BAD_REQUEST);
208                 }
209                 return response.entity(new JsonResponse(lockStatus.getResult()).setLock(lockId).setMessage(lockStatus.getMessage()).toMap()).build();
210             } catch (Exception e) {
211                 logger.error(EELFLoggerDelegate.errorLogger,AppMessages.INVALIDLOCK + lockId, ErrorSeverity.CRITICAL,
212                     ErrorTypes.LOCKINGERROR, e);
213                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Unable to aquire lock").toMap()).build();
214             }
215         } finally {
216             EELFLoggerDelegate.mdcRemove("keyspace");
217         }
218     }
219     
220
221     @POST
222     @Path("/acquire-with-lease/{lockId}")
223     @ApiOperation(
224         hidden = false,
225         value = " ** DEPRECATED ** - Aquire Lock with Lease", 
226         notes = "Acquire the lock with a lease, where lease period is in Milliseconds.\n"
227         + "This will ensure that a lock will expire in set milliseconds.\n"
228         + "This is no longer available after v3.2.0",
229         response = Map.class)
230     @Consumes(MediaType.APPLICATION_JSON)
231     @Produces(MediaType.APPLICATION_JSON) 
232     @ApiResponses(value={
233         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
234             @ExampleProperty(mediaType="application/json",value = 
235                 "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\","
236                 + "\"lock-lease\" : \"6000\"},"
237                 + "\"message\" : \"<integer> is the lock holder for the key\","
238                 + "\"status\" : \"SUCCESS\"}")
239         })),
240         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
241             @ExampleProperty(mediaType="application/json",value = 
242                 "{\"error\" : \"Unable to aquire lock\","
243                 + "\"status\" : \"FAILURE\"}") 
244         }))
245     })  
246     @Deprecated
247     public Response accquireLockWithLease(
248         JsonLeasedLock lockObj, 
249         @ApiParam(value="Lock Id",required=true) @PathParam("lockId") String lockId,
250         @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
251         @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
252         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
253         @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
254         @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{
255         try {
256             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
257             Map<String, Object> resultMap = MusicCore.validateLock(lockId);
258             if (resultMap.containsKey("Error")) {
259                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
260                 response.status(Status.BAD_REQUEST);
261                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
262             }
263             String keyspaceName = (String) resultMap.get("keyspace");
264             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
265             String lockName = lockId.substring(lockId.indexOf('$')+1, lockId.lastIndexOf('$'));
266             ReturnType lockLeaseStatus = MusicCore.acquireLockWithLease(lockName, lockId, lockObj.getLeasePeriod());
267             if ( lockLeaseStatus.getResult().equals(ResultType.SUCCESS)) {
268                 response.status(Status.OK);
269             } else {
270                 response.status(Status.BAD_REQUEST);
271             }
272             return response.entity(new JsonResponse(lockLeaseStatus.getResult()).setLock(lockName)
273                 .setMessage(lockLeaseStatus.getMessage())
274                 .setLockLease(String.valueOf(lockObj.getLeasePeriod())).toMap()).build();
275         } finally {
276             EELFLoggerDelegate.mdcRemove("keyspace");
277         }
278
279
280     } 
281     
282
283     @GET
284     @Path("/enquire/{lockname}")
285     @ApiOperation(value = "Get the top of the lock queue", 
286         notes = "Gets the current single lockholder at top of lock queue",
287         response = Map.class)
288     @Produces(MediaType.APPLICATION_JSON)    
289     @ApiResponses(value={
290         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
291             @ExampleProperty(mediaType="application/json",value = 
292                 "{\"lock\" : {\"lock\" : \"keyspace.table.rowId\","
293                 + "\"lock-holder\" : \"$tomtest.employees.tom$<integer>\"}},"
294                 + "\"status\" : \"SUCCESS\"}") 
295         })),
296         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
297             @ExampleProperty(mediaType="application/json",value = 
298                 "{\"error\" : \"Error Message\","
299                 + "\"status\" : \"FAILURE\"}") 
300         }))
301     })  
302     public Response enquireLock(
303             @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
304             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
305             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
306             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
307             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
308             @ApiParam(value = "Application namespace",
309                             required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{
310         try {
311             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
312             Map<String, Object> resultMap = MusicCore.validateLock(lockName);
313             if (resultMap.containsKey("Error")) {
314                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
315                 response.status(Status.BAD_REQUEST);
316                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
317             }
318             String keyspaceName = (String) resultMap.get("keyspace");
319             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
320             String who = MusicCore.whoseTurnIsIt(lockName);
321             ResultType status = ResultType.SUCCESS;
322             String error = "";
323             if ( who == null ) { 
324                 status = ResultType.FAILURE; 
325                 error = "There was a problem getting the lock holder";
326                 logger.error(EELFLoggerDelegate.errorLogger,"There was a problem getting the lock holder", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
327                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build();
328             }
329             return response.status(Status.OK).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build();
330         } finally {
331             EELFLoggerDelegate.mdcRemove("keyspace");
332         }
333     }
334
335     @GET
336     @Path("/holders/{lockname}")
337     @ApiOperation(value = "Get Lock Holders", 
338         notes = "Gets the current Lock Holders.\n"
339         + "Will return an array of READ Lock References.",
340         response = Map.class)
341     @Produces(MediaType.APPLICATION_JSON)    
342     @ApiResponses(value={
343         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
344             @ExampleProperty(mediaType="application/json",value = 
345                 "{\"lock\" : {\"lock\" : \"keyspace.table.rowId\","
346                 + "\"lock-holder\" : [\"$keyspace.table.rowId$<integer1>\",\"$keyspace.table.rowId$<integer2>\"]}},"
347                 + "\"status\" : \"SUCCESS\"}") 
348         })),
349         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
350             @ExampleProperty(mediaType="application/json",value = 
351                 "{\"error\" : \"Error message\","
352                 + "\"status\" : \"FAILURE\"}") 
353         }))
354     })  
355     public Response currentLockHolder(@ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
356             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
357             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
358             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
359             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
360             @ApiParam(value = "Application namespace",
361                             required = false, hidden = true) @HeaderParam("ns") String ns) {
362         try {
363             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
364             Map<String, Object> resultMap = MusicCore.validateLock(lockName);
365             if (resultMap.containsKey("Error")) {
366                 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA, ErrorSeverity.CRITICAL,
367                         ErrorTypes.GENERALSERVICEERROR);
368                 response.status(Status.BAD_REQUEST);
369                 return response.entity(
370                         new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap())
371                         .build();
372             }
373             String keyspaceName = (String) resultMap.get("keyspace");
374             List<String> who = MusicCore.getCurrentLockHolders(lockName);
375             ResultType status = ResultType.SUCCESS;
376             String error = "";
377             if (who == null || who.isEmpty()) {
378                 status = ResultType.FAILURE;
379                 error = (who !=null && who.isEmpty()) ? "No lock holders for the key":"There was a problem getting the lock holder";
380                 logger.error(EELFLoggerDelegate.errorLogger, "There was a problem getting the lock holder",
381                         AppMessages.INCORRECTDATA, ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
382                 return response.status(Status.BAD_REQUEST)
383                         .entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap())
384                         .build();
385             }
386             return response.status(Status.OK)
387                 .entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).setisLockHolders(true).toMap())
388                 .build();
389         } finally {
390             EELFLoggerDelegate.mdcRemove("keyspace");
391         }
392     }
393     
394     
395     @GET
396     @Path("/{lockname}")
397     @ApiOperation(value = "Lock State",
398         notes = "Returns current Lock State and Holder.",
399         response = Map.class,hidden = true)
400     @Produces(MediaType.APPLICATION_JSON)    
401     @ApiResponses(value={
402         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
403             @ExampleProperty(mediaType="application/json",value = 
404                 "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"},"
405                 + "\"message\" : \"<integer> is the lock holder for the key\","
406                 + "\"status\" : \"SUCCESS\"}") 
407         })),
408         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
409             @ExampleProperty(mediaType="application/json",value = 
410                 "{\"error\" : \"Unable to aquire lock\","
411                 + "\"status\" : \"FAILURE\"}") 
412         }))
413     })  
414     public Response currentLockState(
415             @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
416             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
417             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
418             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
419             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
420             @ApiParam(value = "Application namespace",
421                             required = false, hidden = true) @HeaderParam("ns") String ns) {
422         try {
423             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
424             Map<String, Object> resultMap = MusicCore.validateLock(lockName);
425             if (resultMap.containsKey("Error")) {
426                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
427                 response.status(Status.BAD_REQUEST);
428                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
429             }
430             String keyspaceName = (String) resultMap.get("keyspace");
431             EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) ");
432             String who = MusicCore.whoseTurnIsIt(lockName);
433             ResultType status = ResultType.SUCCESS;
434             String error = "";
435             if ( who == null ) {
436                 status = ResultType.FAILURE; 
437                 error = "There was a problem getting the lock holder";
438                 logger.error(EELFLoggerDelegate.errorLogger,"There was a problem getting the lock holder", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
439                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build();
440             }
441             return response.status(Status.OK).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build();
442         } finally {
443             EELFLoggerDelegate.mdcRemove("keyspace");
444         }
445
446     }
447
448     /**
449      * 
450      * deletes the process from the lock queue
451      * 
452      * @param lockId
453      * @throws Exception 
454      */
455     @DELETE
456     @Path("/release/{lockreference}")
457     @ApiOperation(value = "Release Lock",
458         notes = "Releases the lock from the lock queue.",
459         response = Map.class)
460     @Produces(MediaType.APPLICATION_JSON)    
461     @ApiResponses(value={
462         @ApiResponse(code=200, message = "Success - UNLOCKED = Lock Removed.",examples = @Example( value =  {
463             @ExampleProperty(mediaType="application/json",value = 
464                 "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"},"
465                 + "\"lock-status\" : \"UNLOCKED\"},"
466                 + "\"status\" : \"SUCCESS\"}")
467         })),
468         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
469             @ExampleProperty(mediaType="application/json",value = 
470                 "{\"error\" : \"Unable to aquire lock\","
471                 + "\"status\" : \"FAILURE\"}") 
472         }))
473     })  
474     public Response unLock(@PathParam("lockreference") String lockId,
475             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
476             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
477             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
478             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
479             @ApiParam(value = "Application namespace",
480                 required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{
481         try {
482             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
483             Map<String, Object> resultMap = MusicCore.validateLock(lockId);
484             if (resultMap.containsKey("Error")) {
485                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
486                 response.status(Status.BAD_REQUEST);
487                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
488             }
489
490             String keyspaceName = (String) resultMap.get("keyspace");
491             EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) ");
492             boolean voluntaryRelease = true; 
493             MusicLockState mls = MusicCore.releaseLock(lockId,voluntaryRelease);
494             if(mls.getErrorMessage() != null) {
495                 resultMap.put(ResultType.EXCEPTION.getResult(), mls.getErrorMessage());
496                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
497                 return response.status(Status.BAD_REQUEST).entity(resultMap).build();
498             }
499             Map<String,Object> returnMap = null;
500             if (mls.getLockStatus() == MusicLockState.LockStatus.UNLOCKED) {
501                 returnMap = new JsonResponse(ResultType.SUCCESS).setLock(lockId)
502                     .setLockStatus(mls.getLockStatus()).toMap();
503                 response.status(Status.OK);
504             }
505             if (mls.getLockStatus() == MusicLockState.LockStatus.LOCKED) {
506                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.LOCKINGERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
507                 returnMap = new JsonResponse(ResultType.FAILURE).setLock(lockId)
508                     .setLockStatus(mls.getLockStatus()).toMap();
509                 response.status(Status.BAD_REQUEST);
510             }
511             return response.entity(returnMap).build();
512         } finally {
513             EELFLoggerDelegate.mdcRemove("keyspace");
514         }
515     }
516
517     /**
518      * 
519      * @param lockName
520      * @throws Exception 
521      */
522     @Deprecated
523     @DELETE
524     @Path("/delete/{lockname}")
525     @ApiOperation(
526         hidden = true,
527         value = "-DEPRECATED- Delete Lock", response = Map.class,
528         notes = "-DEPRECATED- Delete the lock.")
529     @Produces(MediaType.APPLICATION_JSON)    
530     @ApiResponses(value={
531         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
532             @ExampleProperty(mediaType="application/json",value = 
533                 "{\"status\" : \"SUCCESS\"}") 
534         })),
535         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
536             @ExampleProperty(mediaType="application/json",value = 
537                 "{\"error\" : \"Error Message if any\","
538                 + "\"status\" : \"FAILURE\"}") 
539         }))
540     })
541     public Response deleteLock(@PathParam("lockname") String lockName,
542             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
543             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
544             @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid,
545             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
546             @ApiParam(value = "Application namespace",
547                             required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{
548         try {
549             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
550             Map<String, Object> resultMap = MusicCore.validateLock(lockName);
551             if (resultMap.containsKey("Error")) {
552                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
553                 response.status(Status.BAD_REQUEST);
554                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
555             }
556
557             String keyspaceName = (String) resultMap.get("keyspace");
558             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
559             try{
560                 MusicCore.destroyLockRef(lockName);
561             }catch (Exception e) {
562                 logger.error(EELFLoggerDelegate.errorLogger, e);
563                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build();
564             }
565             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).toMap()).build();
566         } finally {
567             EELFLoggerDelegate.mdcRemove("keyspace");
568         }
569     }
570
571     
572     /**
573      * Puts the requesting process in the q for this lock. The corresponding
574      * node will be created if it did not already exist
575      * 
576      * @param lockName
577      * @return
578      * @throws Exception 
579      */
580     @POST
581     @Path("/promote/{lockname}")
582     @ApiOperation(value = "Attempt to promote the lock for a single row.",
583         response = Map.class)
584     @Consumes(MediaType.APPLICATION_JSON)
585     @Produces(MediaType.APPLICATION_JSON)
586     @ApiResponses(value={
587         @ApiResponse(code=200, message = "Success",examples = @Example( value =  {
588             @ExampleProperty(mediaType="application/json",value = 
589                 "\"status\" : \"SUCCESS\"}")
590         })),
591         @ApiResponse(code=400, message = "Failure",examples = @Example( value =  {
592             @ExampleProperty(mediaType="application/json",value = 
593                 "{\"error\" : \"Unable to promote lock\","
594                 + "\"status\" : \"FAILURE\"}") 
595         }))
596     })  
597     public Response promoteLock(
598             @ApiParam(value="Lock Id",required=true) @PathParam("lockId") String lockId,
599             @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion,
600             @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion,
601             @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization)
602                     throws Exception {
603         try { 
604             ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion);
605             Map<String, Object> resultMap = MusicCore.validateLock(lockId);
606             if (resultMap.containsKey("Error")) {
607                 logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA  ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR);
608                 response.status(Status.BAD_REQUEST);
609                 return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build();
610             }
611             
612             String keyspaceName = (String) resultMap.get("keyspace");
613             EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) ");
614             
615             try {
616                 ReturnType lockStatus = MusicCore.promoteLock(lockId);
617                 if ( lockStatus.getResult().equals(ResultType.SUCCESS)) {
618                     response.status(Status.OK);
619                 } else {
620                     response.status(Status.BAD_REQUEST);
621                 }
622                 return response.entity(new JsonResponse(lockStatus.getResult()).setLock(lockId).setMessage(lockStatus.getMessage()).toMap()).build();
623             } catch (Exception e) {
624                 logger.error(EELFLoggerDelegate.errorLogger,AppMessages.INVALIDLOCK + lockId, ErrorSeverity.CRITICAL,
625                     ErrorTypes.LOCKINGERROR, e);
626                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Unable to promote lock").toMap()).build();
627             }
628         } finally {
629             EELFLoggerDelegate.mdcRemove("keyspace");
630         }
631     }
632 }