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