b312af30eebe1c953b2fc949451bf04d50b9d27c
[aai/champ.git] / champ-service / src / main / java / org / onap / champ / ChampRESTAPI.java
1 /**
2  * ============LICENSE_START==========================================
3  * org.onap.aai
4  * ===================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
7  * ===================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END============================================
20  */
21 package org.onap.champ;
22
23 import java.io.IOException;
24 import java.security.NoSuchAlgorithmException;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import java.util.Timer;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.ws.rs.Consumes;
35 import javax.ws.rs.DELETE;
36 import javax.ws.rs.GET;
37 import javax.ws.rs.POST;
38 import javax.ws.rs.PUT;
39 import javax.ws.rs.Path;
40 import javax.ws.rs.PathParam;
41 import javax.ws.rs.Produces;
42 import javax.ws.rs.QueryParam;
43 import javax.ws.rs.core.Context;
44 import javax.ws.rs.core.EntityTag;
45 import javax.ws.rs.core.HttpHeaders;
46 import javax.ws.rs.core.MediaType;
47 import javax.ws.rs.core.Response;
48 import javax.ws.rs.core.Response.Status;
49 import javax.ws.rs.core.UriInfo;
50 import org.json.JSONException;
51 import org.json.JSONObject;
52 import org.onap.aai.champcore.ChampTransaction;
53 import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
54 import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
55 import org.onap.aai.champcore.exceptions.ChampTransactionException;
56 import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
57 import org.onap.aai.champcore.model.ChampObject;
58 import org.onap.aai.champcore.model.ChampRelationship;
59 import org.onap.aai.cl.api.Logger;
60 import org.onap.aai.cl.eelf.LoggerFactory;
61 import org.onap.champ.async.ChampAsyncRequestProcessor;
62 import org.onap.champ.entity.ChampObjectDeserializer;
63 import org.onap.champ.entity.ChampObjectSerializer;
64 import org.onap.champ.entity.ChampRelationshipDeserializer;
65 import org.onap.champ.entity.ChampRelationshipSerializer;
66 import org.onap.champ.exception.ChampServiceException;
67 import org.onap.champ.service.ChampDataService;
68 import org.onap.champ.service.logging.ChampMsgs;
69 import org.onap.champ.service.logging.LoggingUtil;
70 import org.onap.champ.util.ChampProperties;
71 import org.onap.champ.util.ChampServiceConstants;
72 import org.onap.champ.util.HttpHeadersValidator;
73 import org.onap.champ.util.etag.EtagGenerator;
74 import com.fasterxml.jackson.core.JsonProcessingException;
75 import com.fasterxml.jackson.databind.ObjectMapper;
76 import com.fasterxml.jackson.databind.module.SimpleModule;
77
78 @Path(value = "/services/champ-service/v1/")
79 public class ChampRESTAPI {
80
81   private ObjectMapper mapper;
82
83   private ChampDataService champDataService;
84   private EtagGenerator etagGenerator;
85   private HttpHeadersValidator httpHeadersValidator;
86   private String TRANSACTION_METHOD = "method";
87   private Timer timer;
88
89   private Logger logger = LoggerFactory.getInstance().getLogger(ChampRESTAPI.class);
90   Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(ChampRESTAPI.class.getName());
91   private static Logger metricsLogger = LoggerFactory.getInstance().getMetricsLogger(ChampRESTAPI.class.getName());
92   private static final Pattern QUERY_OBJECT_ID_URL_MATCH = Pattern.compile("_reserved_(.*)");
93
94   public ChampRESTAPI(ChampDataService champDataService, ChampAsyncRequestProcessor champAsyncRequestProcessor) throws NoSuchAlgorithmException {
95     this.champDataService = champDataService;
96
97     // Async request handling is optional.
98     if (champAsyncRequestProcessor != null) {
99       timer = new Timer("ChampAsyncRequestProcessor-1");
100       timer.schedule(champAsyncRequestProcessor, champAsyncRequestProcessor.getRequestPollingTimeSeconds(),
101           champAsyncRequestProcessor.getRequestPollingTimeSeconds());
102     }
103
104     mapper = new ObjectMapper();
105     SimpleModule module = new SimpleModule();
106     module.addSerializer(ChampObject.class, new ChampObjectSerializer());
107     module.addDeserializer(ChampObject.class, new ChampObjectDeserializer());
108     module.addSerializer(ChampRelationship.class, new ChampRelationshipSerializer());
109     module.addDeserializer(ChampRelationship.class, new ChampRelationshipDeserializer());
110     mapper.registerModule(module);
111
112     etagGenerator = new EtagGenerator();
113     httpHeadersValidator = new HttpHeadersValidator();
114   }
115
116   @GET
117   @Path("echo")
118   @Produces(MediaType.TEXT_PLAIN)
119   public Response echo() {
120     return Response.ok().entity("alive").build();
121   }
122
123   @GET
124   @Path("objects/{objectId}")
125   @Produces(MediaType.APPLICATION_JSON)
126   public Response getObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId,
127       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
128     LoggingUtil.initMdcContext(req, headers);
129     long startTimeInMs = System.currentTimeMillis();
130     logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId);
131
132     Response response = null;
133     ChampObject retrieved;
134
135     try {
136       httpHeadersValidator.validateRequestHeaders(headers);
137       ChampTransaction transaction = champDataService.getTransaction(tId);
138
139       if (tId != null && transaction == null) {
140         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
141       }
142       retrieved = champDataService.getObject(objectId, Optional.ofNullable(transaction));
143       if (retrieved == null) {
144         response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build();
145       } else {
146         EntityTag etag = new EntityTag(etagGenerator.computeHashForChampObject(retrieved));
147         response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).tag(etag).build();
148       }
149
150     } catch (JsonProcessingException e) {
151       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
152     } catch (ChampServiceException ce) {
153       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
154     } catch (Exception e) {
155         response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
156         LoggingUtil.logInternalError(logger, e);
157     } finally {
158       logger.debug(response.getEntity().toString());
159       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
160       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
161     }
162
163     return response;
164   }
165
166   @DELETE
167   @Path("objects/{objectId}")
168   public Response deleteObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId,
169       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
170     LoggingUtil.initMdcContext(req, headers);
171     long startTimeInMs = System.currentTimeMillis();
172     logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId);
173     Response response = null;
174     try {
175       httpHeadersValidator.validateRequestHeaders(headers);
176       ChampTransaction transaction = champDataService.getTransaction(tId);
177
178       if (tId != null && transaction == null) {
179         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
180       }
181       champDataService.deleteObject(objectId, Optional.ofNullable(transaction));
182
183       response = Response.status(Status.OK).build();
184     } catch (ChampObjectNotExistsException e) {
185       response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build();
186     } catch (ChampServiceException ce) {
187       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
188     } catch (ChampTransactionException | ChampUnmarshallingException e) {
189       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
190     } finally {
191       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
192       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE",
193           Long.toString(System.currentTimeMillis() - startTimeInMs));
194     }
195     return response;
196   }
197
198   @POST
199   @Path("objects")
200   @Consumes(MediaType.APPLICATION_JSON)
201   @Produces(MediaType.APPLICATION_JSON)
202   public Response postObject(String champObj, @QueryParam("transactionId") String tId, @Context HttpHeaders headers,
203       @Context UriInfo uriInfo, @Context HttpServletRequest req) {
204     LoggingUtil.initMdcContext(req, headers);
205     long startTimeInMs = System.currentTimeMillis();
206     logger.info(ChampMsgs.INCOMING_REQUEST, tId, champObj);
207     Response response = null;
208     try {
209       httpHeadersValidator.validateRequestHeaders(headers);
210       ChampTransaction transaction = champDataService.getTransaction(tId);
211       if (tId != null && transaction == null) {
212         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
213       }
214       ChampObject champObject = mapper.readValue(champObj, ChampObject.class);
215
216       ChampObject created = champDataService.storeObject(champObject, Optional.ofNullable(transaction));
217       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObject(created));
218       response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).tag(eTag).build();
219     } catch (IOException e) {
220       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
221     } catch (ChampServiceException ce) {
222       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
223     } catch (IllegalArgumentException e) {
224       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
225     } catch (Exception e) {
226       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
227       LoggingUtil.logInternalError(logger, e);
228     } finally {
229       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
230       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST",
231           Long.toString(System.currentTimeMillis() - startTimeInMs));
232     }
233     return response;
234   }
235
236   @PUT
237   @Path("objects/{objectId}")
238   @Consumes(MediaType.APPLICATION_JSON)
239   @Produces(MediaType.APPLICATION_JSON)
240   public Response putObject(@PathParam("objectId") String objectId, String champObj,
241       @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo,
242       @Context HttpServletRequest req) {
243     LoggingUtil.initMdcContext(req, headers);
244     long startTimeInMs = System.currentTimeMillis();
245     logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId + " " + champObj);
246
247     Response response = null;
248     try {
249       httpHeadersValidator.validateRequestHeaders(headers);
250       ChampTransaction transaction = champDataService.getTransaction(tId);
251       if (tId != null && transaction == null) {
252         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
253       }
254
255       ChampObject co = mapper.readValue(champObj, ChampObject.class);
256       // check if key is present or if it equals the key that is in the URI
257       ChampObject updated = champDataService.replaceObject(co, objectId, Optional.ofNullable(transaction));
258       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObject(updated));
259       response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).tag(eTag).build();
260     } catch (IOException e) {
261       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
262     } catch (ChampServiceException ce) {
263       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
264     } catch (IllegalArgumentException e) {
265       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
266     } catch (Exception e) {
267       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
268       LoggingUtil.logInternalError(logger, e);
269     } finally {
270       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
271       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs));
272     }
273     return response;
274   }
275
276   @GET
277   @Path("objects/relationships/{oId}")
278   @Produces(MediaType.APPLICATION_JSON)
279   public Response getEdges(@PathParam("oId") String oId, @QueryParam("transactionId") String tId,
280       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
281     LoggingUtil.initMdcContext(req, headers);
282     long startTimeInMs = System.currentTimeMillis();
283     List<ChampRelationship> retrieved;
284     Response response = null;
285     ChampTransaction transaction = null;
286     try {
287       httpHeadersValidator.validateRequestHeaders(headers);
288       retrieved = champDataService.getRelationshipsByObject(oId, Optional.ofNullable(transaction));
289       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationships(retrieved));
290       response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).tag(eTag).build();
291     } catch (JsonProcessingException e) {
292       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
293     } catch (ChampServiceException ce) {
294       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
295     } catch (Exception e) {
296       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
297       LoggingUtil.logInternalError(logger, e);
298     } finally {
299       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
300       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
301     }
302     return response;
303   }
304
305   @GET
306   @Path("objects/filter/")
307   @Produces(MediaType.APPLICATION_JSON)
308   public Response filterObject(@Context HttpHeaders headers, @Context UriInfo uriInfo,
309       @Context HttpServletRequest req) {
310     LoggingUtil.initMdcContext(req, headers);
311     long startTimeInMs = System.currentTimeMillis();
312     String propertiesKey = ChampProperties.get(ChampServiceConstants.CHAMP_COLLECTION_PROPERTIES_KEY);
313     List<ChampObject> champObjects;
314     Map<String, Object> filter = new HashMap<>();
315
316     for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
317       if ((!e.getKey().equals(propertiesKey)) && !reservedKeyMatcher ( QUERY_OBJECT_ID_URL_MATCH, e.getKey () )) {
318         filter.put(e.getKey(), e.getValue().get(0));
319       }
320     }
321
322     HashSet<String> properties;
323     if (uriInfo.getQueryParameters().containsKey(propertiesKey)) {
324       properties = new HashSet<>(uriInfo.getQueryParameters().get(propertiesKey));
325     } else {
326       properties = new HashSet<>();
327     }
328
329     Response response = null;
330     try {
331       httpHeadersValidator.validateRequestHeaders(headers);
332       champObjects = champDataService.queryObjects(filter, properties);
333       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObjects(champObjects));
334       response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).tag(eTag).entity(mapper.writeValueAsString(champObjects))
335           .build();
336     } catch (JsonProcessingException e) {
337       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
338     } catch (ChampServiceException e1) {
339       response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build();
340     } catch (Exception e) {
341       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
342       LoggingUtil.logInternalError(logger, e);
343     } finally {
344       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
345       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
346     }
347     return response;
348   }
349
350   @GET
351   @Path("relationships/{rId}")
352   @Produces(MediaType.APPLICATION_JSON)
353   public Response getRelationship(@PathParam("rId") String rId, @QueryParam("transactionId") String tId,
354       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
355     LoggingUtil.initMdcContext(req, headers);
356     long startTimeInMs = System.currentTimeMillis();
357     logger.info(ChampMsgs.INCOMING_REQUEST, tId, rId);
358     ChampRelationship retrieved;
359     Response response = null;
360     try {
361       httpHeadersValidator.validateRequestHeaders(headers);
362       ChampTransaction transaction = champDataService.getTransaction(tId);
363
364       if (tId != null && transaction == null) {
365         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
366       }
367       retrieved = champDataService.getRelationship(rId, Optional.ofNullable(transaction));
368       if (retrieved == null) {
369         response = Response.status(Status.NOT_FOUND).entity(rId + " not found").build();
370         return response;
371       }
372       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationship(retrieved));
373       response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).tag(eTag).build();
374
375     } catch (IOException e) {
376       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
377     } catch (ChampServiceException ce) {
378       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
379     } catch (Exception e) {
380       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
381       LoggingUtil.logInternalError(logger, e);
382     } finally {
383       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
384       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
385     }
386     return response;
387   }
388
389   @POST
390   @Path("relationships")
391   @Consumes(MediaType.APPLICATION_JSON)
392   @Produces(MediaType.APPLICATION_JSON)
393   public Response postRelationships(String relationship, @QueryParam("transactionId") String tId,
394       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
395     LoggingUtil.initMdcContext(req, headers);
396     long startTimeInMs = System.currentTimeMillis();
397     logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship);
398     Response response = null;
399     try {
400       httpHeadersValidator.validateRequestHeaders(headers);
401       ChampTransaction transaction = champDataService.getTransaction(tId);
402       if (tId != null && transaction == null) {
403         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
404       }
405       ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class);
406
407       ChampRelationship created = champDataService.storeRelationship(r, Optional.ofNullable(transaction));
408       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationship(created));
409       response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).tag(eTag).build();
410     } catch (IOException e) {
411       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
412     } catch (ChampServiceException ce) {
413       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
414     } catch (IllegalArgumentException e) {
415       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
416     } catch (Exception e) {
417       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
418       LoggingUtil.logInternalError(logger, e);
419     } finally {
420       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
421       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST",
422           Long.toString(System.currentTimeMillis() - startTimeInMs));
423     }
424     return response;
425   }
426
427   @PUT
428   @Path("relationships/{rId}")
429   @Consumes(MediaType.APPLICATION_JSON)
430   @Produces(MediaType.APPLICATION_JSON)
431   public Response updateRelationship(@PathParam("rId") String rId, String relationship,
432       @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo,
433       @Context HttpServletRequest req) {
434     LoggingUtil.initMdcContext(req, headers);
435     long startTimeInMs = System.currentTimeMillis();
436     logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship);
437
438     Response response = null;
439     try {
440       httpHeadersValidator.validateRequestHeaders(headers);
441       ChampTransaction transaction = champDataService.getTransaction(tId);
442       if (tId != null && transaction == null) {
443         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
444       }
445       ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class);
446       ChampRelationship updated = champDataService.updateRelationship(r, rId, Optional.ofNullable(transaction));
447       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationship(updated));
448       response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).tag(eTag).build();
449     } catch (IOException e) {
450       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
451     } catch (ChampServiceException ce) {
452       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
453     } catch (IllegalArgumentException e) {
454       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
455     } catch (Exception e) {
456       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
457       LoggingUtil.logInternalError(logger, e);
458     } finally {
459       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
460       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs));
461     }
462     return response;
463   }
464
465   @DELETE
466   @Path("relationships/{relationshipId}")
467   public Response deleteRelationship(@PathParam("relationshipId") String relationshipId,
468       @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo,
469       @Context HttpServletRequest req) {
470     LoggingUtil.initMdcContext(req, headers);
471     long startTimeInMs = System.currentTimeMillis();
472     logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationshipId);
473
474     Response response = null;
475     try {
476       httpHeadersValidator.validateRequestHeaders(headers);
477       ChampTransaction transaction = champDataService.getTransaction(tId);
478       if (tId != null && transaction == null) {
479         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
480       }
481       champDataService.deleteRelationship(relationshipId, Optional.ofNullable(transaction));
482       response = Response.status(Status.OK).build();
483
484     } catch (ChampRelationshipNotExistsException e) {
485       response = Response.status(Status.NOT_FOUND).entity(relationshipId + " not found").build();
486     } catch (ChampServiceException ce) {
487       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
488     } catch (ChampTransactionException | ChampUnmarshallingException e) {
489       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
490     } finally {
491       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
492       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE",
493           Long.toString(System.currentTimeMillis() - startTimeInMs));
494     }
495     return response;
496   }
497
498   @GET
499   @Path("relationships/filter/")
500   @Produces(MediaType.APPLICATION_JSON)
501   public Response filterMethod(@Context HttpHeaders headers, @Context UriInfo uriInfo,
502       @Context HttpServletRequest req) {
503     LoggingUtil.initMdcContext(req, headers);
504     long startTimeInMs = System.currentTimeMillis();
505     List<ChampRelationship> champRelationshipList;
506     Map<String, Object> filter = new HashMap<>();
507     for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
508       if (!reservedKeyMatcher ( QUERY_OBJECT_ID_URL_MATCH, e.getKey () )) {
509         filter.put ( e.getKey (), e.getValue ().get ( 0 ) );
510       }
511     }
512     Response response = null;
513     try {
514       httpHeadersValidator.validateRequestHeaders(headers);
515       champRelationshipList = champDataService.queryRelationships(filter);
516       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationships(champRelationshipList));
517       response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).tag(eTag).entity(mapper.writeValueAsString(champRelationshipList))
518           .build();
519     } catch (JsonProcessingException e) {
520       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
521     } catch (ChampServiceException e1) {
522       response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build();
523     } catch (Exception e) {
524       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
525       LoggingUtil.logInternalError(logger, e);
526     } finally {
527       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
528       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
529     }
530     return response;
531   }
532
533   @POST
534   @Path("transaction")
535   @Produces(MediaType.TEXT_PLAIN)
536   public Response openTransaction(@Context HttpHeaders headers, @Context UriInfo uriInfo,
537       @Context HttpServletRequest req) {
538     LoggingUtil.initMdcContext(req, headers);
539     long startTimeInMs = System.currentTimeMillis();
540     Response response = null;
541     try {
542       httpHeadersValidator.validateRequestHeaders(headers);
543       String transaction = champDataService.openTransaction();
544       Status s = Status.OK;
545       response = Response.status(s).entity(transaction).build();
546       logger.info(ChampMsgs.PROCESS_EVENT, "Opened Transaction with ID: " + transaction, s.toString());
547     } catch (ChampServiceException e) {
548       response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
549     } finally {
550       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
551       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", Long.toString(System.currentTimeMillis() - startTimeInMs));
552     }
553     return response;
554   }
555
556   @GET
557   @Path("transaction/{tId}")
558   public Response getSpecificTransaction(@PathParam("tId") String tId, @Context HttpHeaders headers,
559       @Context UriInfo uriInfo, @Context HttpServletRequest req) {
560     LoggingUtil.initMdcContext(req, headers);
561     long startTimeInMs = System.currentTimeMillis();
562
563     Response response = null;
564     ChampTransaction transaction = champDataService.getTransaction(tId);
565     if (transaction == null) {
566       response = Response.status(Status.NOT_FOUND).entity("transaction " + tId + " not found").build();
567       return response;
568     }
569
570     try {
571       httpHeadersValidator.validateRequestHeaders(headers);
572       response = Response.status(Status.OK).entity(mapper.writeValueAsString(tId + " is OPEN")).build();
573     } catch (JsonProcessingException e) {
574       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
575     } catch (ChampServiceException e) {
576         response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
577     } catch (Exception e) {
578       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
579       LoggingUtil.logInternalError(logger, e);
580     } finally {
581       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
582       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
583     }
584     return response;
585   }
586
587   @PUT
588   @Path("transaction/{tId}")
589   @Produces(MediaType.TEXT_PLAIN)
590   @Consumes(MediaType.APPLICATION_JSON)
591   public Response updateTransaction(String t, @PathParam("tId") String tId, @Context HttpHeaders headers,
592       @Context UriInfo uriInfo, @Context HttpServletRequest req) {
593     LoggingUtil.initMdcContext(req, headers);
594     long startTimeInMs = System.currentTimeMillis();
595     logger.info(ChampMsgs.INCOMING_REQUEST, tId, "COMMIT/ROLLBACK");
596
597     Response response = null;
598     try {
599       httpHeadersValidator.validateRequestHeaders(headers);
600       JSONObject jsonObj = new JSONObject(t);
601       String method = jsonObj.getString(this.TRANSACTION_METHOD);
602
603       if (method.equals("commit")) {
604         champDataService.commitTransaction(tId);
605         response = Response.status(Status.OK).entity("COMMITTED").build();
606
607       } else if (method.equals("rollback")) {
608         champDataService.rollbackTransaction(tId);
609         response = Response.status(Status.OK).entity("ROLLED BACK").build();
610       } else {
611         response = Response.status(Status.BAD_REQUEST).entity("Invalid Method: " + method).build();
612         return response;
613       }
614
615     } catch (ChampTransactionException e) {
616       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
617     } catch (JSONException e) {
618       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
619     } catch (ChampServiceException e) {
620       response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
621     } catch (Exception e) {
622       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
623       LoggingUtil.logInternalError(logger, e);
624     } finally {
625       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
626       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs));
627     }
628     return response;
629   }
630
631   private boolean reservedKeyMatcher(Pattern p, String key) {
632     Matcher m = p.matcher ( key );
633     if (m.matches()) {
634       return true;
635     } else {
636       return false;
637     }
638   }
639
640 }