Merge "Fix potential null pointers"
[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       if (response != null) {
159         logger.debug(response.getEntity().toString());
160       }
161       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
162       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
163     }
164
165     return response;
166   }
167
168   @DELETE
169   @Path("objects/{objectId}")
170   public Response deleteObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId,
171       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
172     LoggingUtil.initMdcContext(req, headers);
173     long startTimeInMs = System.currentTimeMillis();
174     logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId);
175     Response response = null;
176     try {
177       httpHeadersValidator.validateRequestHeaders(headers);
178       ChampTransaction transaction = champDataService.getTransaction(tId);
179
180       if (tId != null && transaction == null) {
181         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
182       }
183       champDataService.deleteObject(objectId, Optional.ofNullable(transaction));
184
185       response = Response.status(Status.OK).build();
186     } catch (ChampObjectNotExistsException e) {
187       response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build();
188     } catch (ChampServiceException ce) {
189       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
190     } catch (ChampTransactionException | ChampUnmarshallingException e) {
191       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
192     } finally {
193       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
194       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE",
195           Long.toString(System.currentTimeMillis() - startTimeInMs));
196     }
197     return response;
198   }
199
200   @POST
201   @Path("objects")
202   @Consumes(MediaType.APPLICATION_JSON)
203   @Produces(MediaType.APPLICATION_JSON)
204   public Response postObject(String champObj, @QueryParam("transactionId") String tId, @Context HttpHeaders headers,
205       @Context UriInfo uriInfo, @Context HttpServletRequest req) {
206     LoggingUtil.initMdcContext(req, headers);
207     long startTimeInMs = System.currentTimeMillis();
208     logger.info(ChampMsgs.INCOMING_REQUEST, tId, champObj);
209     Response response = null;
210     try {
211       httpHeadersValidator.validateRequestHeaders(headers);
212       ChampTransaction transaction = champDataService.getTransaction(tId);
213       if (tId != null && transaction == null) {
214         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
215       }
216       ChampObject champObject = mapper.readValue(champObj, ChampObject.class);
217
218       ChampObject created = champDataService.storeObject(champObject, Optional.ofNullable(transaction));
219       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObject(created));
220       response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).tag(eTag).build();
221     } catch (IOException e) {
222       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
223     } catch (ChampServiceException ce) {
224       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
225     } catch (IllegalArgumentException e) {
226       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
227     } catch (Exception e) {
228       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
229       LoggingUtil.logInternalError(logger, e);
230     } finally {
231       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
232       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST",
233           Long.toString(System.currentTimeMillis() - startTimeInMs));
234     }
235     return response;
236   }
237
238   @PUT
239   @Path("objects/{objectId}")
240   @Consumes(MediaType.APPLICATION_JSON)
241   @Produces(MediaType.APPLICATION_JSON)
242   public Response putObject(@PathParam("objectId") String objectId, String champObj,
243       @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo,
244       @Context HttpServletRequest req) {
245     LoggingUtil.initMdcContext(req, headers);
246     long startTimeInMs = System.currentTimeMillis();
247     logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId + " " + champObj);
248
249     Response response = null;
250     try {
251       httpHeadersValidator.validateRequestHeaders(headers);
252       ChampTransaction transaction = champDataService.getTransaction(tId);
253       if (tId != null && transaction == null) {
254         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
255       }
256
257       ChampObject co = mapper.readValue(champObj, ChampObject.class);
258       // check if key is present or if it equals the key that is in the URI
259       ChampObject updated = champDataService.replaceObject(co, objectId, Optional.ofNullable(transaction));
260       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObject(updated));
261       response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).tag(eTag).build();
262     } catch (IOException e) {
263       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
264     } catch (ChampServiceException ce) {
265       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
266     } catch (IllegalArgumentException e) {
267       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
268     } catch (Exception e) {
269       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
270       LoggingUtil.logInternalError(logger, e);
271     } finally {
272       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
273       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs));
274     }
275     return response;
276   }
277
278   @GET
279   @Path("objects/relationships/{oId}")
280   @Produces(MediaType.APPLICATION_JSON)
281   public Response getEdges(@PathParam("oId") String oId, @QueryParam("transactionId") String tId,
282       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
283     LoggingUtil.initMdcContext(req, headers);
284     long startTimeInMs = System.currentTimeMillis();
285     List<ChampRelationship> retrieved;
286     Response response = null;
287     ChampTransaction transaction = null;
288     try {
289       httpHeadersValidator.validateRequestHeaders(headers);
290       retrieved = champDataService.getRelationshipsByObject(oId, Optional.ofNullable(transaction));
291       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationships(retrieved));
292       response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).tag(eTag).build();
293     } catch (JsonProcessingException e) {
294       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
295     } catch (ChampServiceException ce) {
296       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
297     } catch (Exception e) {
298       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
299       LoggingUtil.logInternalError(logger, e);
300     } finally {
301       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
302       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
303     }
304     return response;
305   }
306
307   @GET
308   @Path("objects/filter/")
309   @Produces(MediaType.APPLICATION_JSON)
310   public Response filterObject(@Context HttpHeaders headers, @Context UriInfo uriInfo,
311       @Context HttpServletRequest req) {
312     LoggingUtil.initMdcContext(req, headers);
313     long startTimeInMs = System.currentTimeMillis();
314     String propertiesKey = ChampProperties.get(ChampServiceConstants.CHAMP_COLLECTION_PROPERTIES_KEY);
315     List<ChampObject> champObjects;
316     Map<String, Object> filter = new HashMap<>();
317
318     for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
319       if ((!e.getKey().equals(propertiesKey)) && !reservedKeyMatcher ( QUERY_OBJECT_ID_URL_MATCH, e.getKey () )) {
320         filter.put(e.getKey(), e.getValue().get(0));
321       }
322     }
323
324     HashSet<String> properties;
325     if (uriInfo.getQueryParameters().containsKey(propertiesKey)) {
326       properties = new HashSet<>(uriInfo.getQueryParameters().get(propertiesKey));
327     } else {
328       properties = new HashSet<>();
329     }
330
331     Response response = null;
332     try {
333       httpHeadersValidator.validateRequestHeaders(headers);
334       champObjects = champDataService.queryObjects(filter, properties);
335       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObjects(champObjects));
336       response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).tag(eTag).entity(mapper.writeValueAsString(champObjects))
337           .build();
338     } catch (JsonProcessingException e) {
339       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
340     } catch (ChampServiceException e1) {
341       response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build();
342     } catch (Exception e) {
343       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
344       LoggingUtil.logInternalError(logger, e);
345     } finally {
346       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
347       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
348     }
349     return response;
350   }
351
352   @GET
353   @Path("relationships/{rId}")
354   @Produces(MediaType.APPLICATION_JSON)
355   public Response getRelationship(@PathParam("rId") String rId, @QueryParam("transactionId") String tId,
356       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
357     LoggingUtil.initMdcContext(req, headers);
358     long startTimeInMs = System.currentTimeMillis();
359     logger.info(ChampMsgs.INCOMING_REQUEST, tId, rId);
360     ChampRelationship retrieved;
361     Response response = null;
362     try {
363       httpHeadersValidator.validateRequestHeaders(headers);
364       ChampTransaction transaction = champDataService.getTransaction(tId);
365
366       if (tId != null && transaction == null) {
367         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
368       }
369       retrieved = champDataService.getRelationship(rId, Optional.ofNullable(transaction));
370       if (retrieved == null) {
371         response = Response.status(Status.NOT_FOUND).entity(rId + " not found").build();
372         return response;
373       }
374       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationship(retrieved));
375       response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).tag(eTag).build();
376
377     } catch (IOException e) {
378       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
379     } catch (ChampServiceException ce) {
380       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
381     } catch (Exception e) {
382       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
383       LoggingUtil.logInternalError(logger, e);
384     } finally {
385       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
386       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
387     }
388     return response;
389   }
390
391   @POST
392   @Path("relationships")
393   @Consumes(MediaType.APPLICATION_JSON)
394   @Produces(MediaType.APPLICATION_JSON)
395   public Response postRelationships(String relationship, @QueryParam("transactionId") String tId,
396       @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
397     LoggingUtil.initMdcContext(req, headers);
398     long startTimeInMs = System.currentTimeMillis();
399     logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship);
400     Response response = null;
401     try {
402       httpHeadersValidator.validateRequestHeaders(headers);
403       ChampTransaction transaction = champDataService.getTransaction(tId);
404       if (tId != null && transaction == null) {
405         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
406       }
407       ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class);
408
409       ChampRelationship created = champDataService.storeRelationship(r, Optional.ofNullable(transaction));
410       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationship(created));
411       response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).tag(eTag).build();
412     } catch (IOException e) {
413       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
414     } catch (ChampServiceException ce) {
415       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
416     } catch (IllegalArgumentException e) {
417       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
418     } catch (Exception e) {
419       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
420       LoggingUtil.logInternalError(logger, e);
421     } finally {
422       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
423       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST",
424           Long.toString(System.currentTimeMillis() - startTimeInMs));
425     }
426     return response;
427   }
428
429   @PUT
430   @Path("relationships/{rId}")
431   @Consumes(MediaType.APPLICATION_JSON)
432   @Produces(MediaType.APPLICATION_JSON)
433   public Response updateRelationship(@PathParam("rId") String rId, String relationship,
434       @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo,
435       @Context HttpServletRequest req) {
436     LoggingUtil.initMdcContext(req, headers);
437     long startTimeInMs = System.currentTimeMillis();
438     logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship);
439
440     Response response = null;
441     try {
442       httpHeadersValidator.validateRequestHeaders(headers);
443       ChampTransaction transaction = champDataService.getTransaction(tId);
444       if (tId != null && transaction == null) {
445         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
446       }
447       ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class);
448       ChampRelationship updated = champDataService.updateRelationship(r, rId, Optional.ofNullable(transaction));
449       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationship(updated));
450       response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).tag(eTag).build();
451     } catch (IOException e) {
452       response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build();
453     } catch (ChampServiceException ce) {
454       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
455     } catch (IllegalArgumentException e) {
456       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
457     } catch (Exception e) {
458       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
459       LoggingUtil.logInternalError(logger, e);
460     } finally {
461       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
462       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs));
463     }
464     return response;
465   }
466
467   @DELETE
468   @Path("relationships/{relationshipId}")
469   public Response deleteRelationship(@PathParam("relationshipId") String relationshipId,
470       @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo,
471       @Context HttpServletRequest req) {
472     LoggingUtil.initMdcContext(req, headers);
473     long startTimeInMs = System.currentTimeMillis();
474     logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationshipId);
475
476     Response response = null;
477     try {
478       httpHeadersValidator.validateRequestHeaders(headers);
479       ChampTransaction transaction = champDataService.getTransaction(tId);
480       if (tId != null && transaction == null) {
481         throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
482       }
483       champDataService.deleteRelationship(relationshipId, Optional.ofNullable(transaction));
484       response = Response.status(Status.OK).build();
485
486     } catch (ChampRelationshipNotExistsException e) {
487       response = Response.status(Status.NOT_FOUND).entity(relationshipId + " not found").build();
488     } catch (ChampServiceException ce) {
489       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
490     } catch (ChampTransactionException | ChampUnmarshallingException e) {
491       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
492     } finally {
493       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
494       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE",
495           Long.toString(System.currentTimeMillis() - startTimeInMs));
496     }
497     return response;
498   }
499
500   @GET
501   @Path("relationships/filter/")
502   @Produces(MediaType.APPLICATION_JSON)
503   public Response filterMethod(@Context HttpHeaders headers, @Context UriInfo uriInfo,
504       @Context HttpServletRequest req) {
505     LoggingUtil.initMdcContext(req, headers);
506     long startTimeInMs = System.currentTimeMillis();
507     List<ChampRelationship> champRelationshipList;
508     Map<String, Object> filter = new HashMap<>();
509     for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
510       if (!reservedKeyMatcher ( QUERY_OBJECT_ID_URL_MATCH, e.getKey () )) {
511         filter.put ( e.getKey (), e.getValue ().get ( 0 ) );
512       }
513     }
514     Response response = null;
515     try {
516       httpHeadersValidator.validateRequestHeaders(headers);
517       champRelationshipList = champDataService.queryRelationships(filter);
518       EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationships(champRelationshipList));
519       response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).tag(eTag).entity(mapper.writeValueAsString(champRelationshipList))
520           .build();
521     } catch (JsonProcessingException e) {
522       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
523     } catch (ChampServiceException e1) {
524       response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build();
525     } catch (Exception e) {
526       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
527       LoggingUtil.logInternalError(logger, e);
528     } finally {
529       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
530       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
531     }
532     return response;
533   }
534
535   @POST
536   @Path("transaction")
537   @Produces(MediaType.TEXT_PLAIN)
538   public Response openTransaction(@Context HttpHeaders headers, @Context UriInfo uriInfo,
539       @Context HttpServletRequest req) {
540     LoggingUtil.initMdcContext(req, headers);
541     long startTimeInMs = System.currentTimeMillis();
542     Response response = null;
543     try {
544       httpHeadersValidator.validateRequestHeaders(headers);
545       String transaction = champDataService.openTransaction();
546       Status s = Status.OK;
547       response = Response.status(s).entity(transaction).build();
548       logger.info(ChampMsgs.PROCESS_EVENT, "Opened Transaction with ID: " + transaction, s.toString());
549     } catch (ChampServiceException e) {
550       response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
551     } finally {
552       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
553       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", Long.toString(System.currentTimeMillis() - startTimeInMs));
554     }
555     return response;
556   }
557
558   @GET
559   @Path("transaction/{tId}")
560   public Response getSpecificTransaction(@PathParam("tId") String tId, @Context HttpHeaders headers,
561       @Context UriInfo uriInfo, @Context HttpServletRequest req) {
562     LoggingUtil.initMdcContext(req, headers);
563     long startTimeInMs = System.currentTimeMillis();
564
565     Response response = null;
566     ChampTransaction transaction = champDataService.getTransaction(tId);
567     if (transaction == null) {
568       response = Response.status(Status.NOT_FOUND).entity("transaction " + tId + " not found").build();
569       return response;
570     }
571
572     try {
573       httpHeadersValidator.validateRequestHeaders(headers);
574       response = Response.status(Status.OK).entity(mapper.writeValueAsString(tId + " is OPEN")).build();
575     } catch (JsonProcessingException e) {
576       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
577     } catch (ChampServiceException e) {
578         response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
579     } catch (Exception e) {
580       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
581       LoggingUtil.logInternalError(logger, e);
582     } finally {
583       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
584       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs));
585     }
586     return response;
587   }
588
589   @PUT
590   @Path("transaction/{tId}")
591   @Produces(MediaType.TEXT_PLAIN)
592   @Consumes(MediaType.APPLICATION_JSON)
593   public Response updateTransaction(String t, @PathParam("tId") String tId, @Context HttpHeaders headers,
594       @Context UriInfo uriInfo, @Context HttpServletRequest req) {
595     LoggingUtil.initMdcContext(req, headers);
596     long startTimeInMs = System.currentTimeMillis();
597     logger.info(ChampMsgs.INCOMING_REQUEST, tId, "COMMIT/ROLLBACK");
598
599     Response response = null;
600     try {
601       httpHeadersValidator.validateRequestHeaders(headers);
602       JSONObject jsonObj = new JSONObject(t);
603       String method = jsonObj.getString(this.TRANSACTION_METHOD);
604
605       if (method.equals("commit")) {
606         champDataService.commitTransaction(tId);
607         response = Response.status(Status.OK).entity("COMMITTED").build();
608
609       } else if (method.equals("rollback")) {
610         champDataService.rollbackTransaction(tId);
611         response = Response.status(Status.OK).entity("ROLLED BACK").build();
612       } else {
613         response = Response.status(Status.BAD_REQUEST).entity("Invalid Method: " + method).build();
614         return response;
615       }
616
617     } catch (ChampTransactionException e) {
618       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
619     } catch (JSONException e) {
620       response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
621     } catch (ChampServiceException e) {
622       response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
623     } catch (Exception e) {
624       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
625       LoggingUtil.logInternalError(logger, e);
626     } finally {
627       LoggingUtil.logRestRequest(logger, auditLogger, req, response);
628       metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs));
629     }
630     return response;
631   }
632
633   private boolean reservedKeyMatcher(Pattern p, String key) {
634     Matcher m = p.matcher ( key );
635     if (m.matches()) {
636       return true;
637     } else {
638       return false;
639     }
640   }
641
642 }