Allow filtering by reserved properties
[aai/gizmo.git] / src / main / java / org / onap / crud / service / CrudRestService.java
1 /**
2  * ============LICENSE_START=======================================================
3  * Gizmo
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property.
6  * Copyright © 2017 Amdocs
7  * All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * <p>
13  * http://www.apache.org/licenses/LICENSE-2.0
14  * <p>
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  * <p>
22  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23  */
24
25 package org.onap.crud.service;
26
27 import com.google.gson.JsonElement;
28
29 import org.apache.cxf.jaxrs.ext.PATCH;
30 import org.onap.aai.cl.api.Logger;
31 import org.onap.aai.cl.eelf.LoggerFactory;
32 import org.onap.aaiauth.auth.Auth;
33 import org.onap.crud.exception.CrudException;
34 import org.onap.crud.logging.CrudServiceMsgs;
35 import org.onap.crud.logging.LoggingUtil;
36 import org.onap.crud.util.CrudProperties;
37 import org.onap.crud.util.CrudServiceConstants;
38 import org.onap.crud.util.CrudServiceUtil;
39 import org.slf4j.MDC;
40
41 import java.security.cert.X509Certificate;
42 import java.util.ArrayList;
43 import java.util.HashMap;
44 import java.util.HashSet;
45 import java.util.List;
46 import java.util.Map;
47 import javax.security.auth.x500.X500Principal;
48 import javax.servlet.http.HttpServletRequest;
49 import javax.ws.rs.Consumes;
50 import javax.ws.rs.DELETE;
51 import javax.ws.rs.Encoded;
52 import javax.ws.rs.GET;
53 import javax.ws.rs.POST;
54 import javax.ws.rs.PUT;
55 import javax.ws.rs.Path;
56 import javax.ws.rs.PathParam;
57 import javax.ws.rs.Produces;
58 import javax.ws.rs.core.Context;
59 import javax.ws.rs.core.HttpHeaders;
60 import javax.ws.rs.core.MediaType;
61 import javax.ws.rs.core.Response;
62 import javax.ws.rs.core.Response.Status;
63 import javax.ws.rs.core.UriInfo;
64
65 public class CrudRestService {
66
67   private AbstractGraphDataService graphDataService;
68   Logger logger = LoggerFactory.getInstance().getLogger(CrudRestService.class.getName());
69   Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(CrudRestService.class.getName());
70   private Auth auth;
71
72   private String mediaType = MediaType.APPLICATION_JSON;
73   public static final String HTTP_PATCH_METHOD_OVERRIDE = "X-HTTP-Method-Override";
74
75   public CrudRestService(AbstractGraphDataService graphDataService) throws Exception {
76     this.graphDataService = graphDataService;
77     this.auth = new Auth(CrudServiceConstants.CRD_AUTH_FILE);
78   }
79
80   public enum Action {
81     POST, GET, PUT, DELETE, PATCH
82   }
83
84   public void startup() {
85
86   }
87
88   @GET
89   @Path("/{version}/{type}/{id}")
90   @Consumes({MediaType.APPLICATION_JSON})
91   @Produces({MediaType.APPLICATION_JSON})
92   public Response getVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
93                             @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
94                             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
95     LoggingUtil.initMdcContext(req, headers);
96
97     logger.debug("Incoming request..." + content);
98     Response response = null;
99
100
101     try {
102       if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
103         String result = graphDataService.getVertex(version, id, type);
104         response = Response.status(Status.OK).entity(result).type(mediaType).build();
105       } else {
106         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
107       }
108     } catch (CrudException ce) {
109       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
110     } catch (Exception e) {
111       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
112
113     }
114
115     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
116     return response;
117   }
118
119   @GET
120   @Path("/{version}/{type}/")
121   @Consumes({MediaType.APPLICATION_JSON})
122   @Produces({MediaType.APPLICATION_JSON})
123   public Response getVertices(String content, @PathParam("version") String version, @PathParam("type") String type,
124                               @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
125                               @Context HttpServletRequest req) {
126
127     LoggingUtil.initMdcContext(req, headers);
128
129     logger.debug("Incoming request..." + content);
130     Response response = null;
131     try {
132       if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
133         String propertiesKey = CrudProperties.get(CrudServiceConstants.CRD_COLLECTION_PROPERTIES_KEY);
134
135         Map<String, String> filter = new HashMap<String, String>();
136
137         for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
138           if (!e.getKey().equals(propertiesKey)) {
139             filter.put(e.getKey(), e.getValue().get(0));
140           }
141         }
142
143         HashSet<String> properties;
144         if (uriInfo.getQueryParameters().containsKey(propertiesKey)) {
145           properties = new HashSet<>(uriInfo.getQueryParameters().get(propertiesKey));
146         } else {
147           properties = new HashSet<>();
148         }
149
150         String result = graphDataService.getVertices(version, type, filter, properties);
151         response = Response.status(Status.OK).entity(result).type(mediaType).build();
152       } else {
153         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
154       }
155     } catch (CrudException ce) {
156       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
157     } catch (Exception e) {
158       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
159
160     }
161
162     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
163     return response;
164   }
165
166   @GET
167   @Path("/relationships/{version}/{type}/{id}")
168   @Consumes({MediaType.APPLICATION_JSON})
169   @Produces({MediaType.APPLICATION_JSON})
170   public Response getEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
171                           @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
172                           @Context UriInfo uriInfo, @Context HttpServletRequest req) {
173     LoggingUtil.initMdcContext(req, headers);
174
175     logger.debug("Incoming request..." + content);
176     Response response = null;
177
178
179     try {
180       if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
181
182         String result = graphDataService.getEdge(version, id, type);
183         response = Response.status(Status.OK).entity(result).type(mediaType).build();
184       } else {
185         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
186       }
187     } catch (CrudException ce) {
188       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
189     } catch (Exception e) {
190       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
191     }
192
193     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
194     return response;
195   }
196
197   @GET
198   @Path("/relationships/{version}/{type}/")
199   @Consumes({MediaType.APPLICATION_JSON})
200   @Produces({MediaType.APPLICATION_JSON})
201   public Response getEdges(String content, @PathParam("version") String version, @PathParam("type") String type,
202                            @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
203                            @Context HttpServletRequest req) {
204
205     LoggingUtil.initMdcContext(req, headers);
206
207     logger.debug("Incoming request..." + content);
208     Response response = null;
209
210
211     Map<String, String> filter = new HashMap<String, String>();
212     for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
213       filter.put(e.getKey(), e.getValue().get(0));
214     }
215
216     try {
217       if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
218         String result = graphDataService.getEdges(version, type, filter);
219         response = Response.status(Status.OK).entity(result).type(mediaType).build();
220       } else {
221         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
222       }
223     } catch (CrudException ce) {
224       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
225     } catch (Exception e) {
226       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
227     }
228
229     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
230     return response;
231   }
232
233   @PUT
234   @Path("/relationships/{version}/{type}/{id}")
235   @Consumes({MediaType.APPLICATION_JSON})
236   @Produces({MediaType.APPLICATION_JSON})
237   public Response updateEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
238                              @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
239                              @Context UriInfo uriInfo, @Context HttpServletRequest req) {
240
241     LoggingUtil.initMdcContext(req, headers);
242
243     logger.debug("Incoming request..." + content);
244     Response response = null;
245
246
247     try {
248       if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
249         EdgePayload payload = EdgePayload.fromJson(content);
250         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
251           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
252         }
253         if (payload.getId() != null && !payload.getId().equals(id)) {
254           throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
255         }
256         String result;
257
258         if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null
259             && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
260           result = graphDataService.patchEdge(version, id, type, payload);
261         } else {
262
263           result = graphDataService.updateEdge(version, id, type, payload);
264         }
265
266         response = Response.status(Status.OK).entity(result).type(mediaType).build();
267       } else {
268         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
269       }
270     } catch (CrudException ce) {
271       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
272     } catch (Exception e) {
273       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
274     }
275
276     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
277     return response;
278   }
279
280   @PATCH
281   @Path("/relationships/{version}/{type}/{id}")
282   @Consumes({"application/merge-patch+json"})
283   @Produces({MediaType.APPLICATION_JSON})
284   public Response patchEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
285                             @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
286                             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
287
288     LoggingUtil.initMdcContext(req, headers);
289
290     logger.debug("Incoming request..." + content);
291     Response response = null;
292
293     try {
294       if (validateRequest(req, uri, content, Action.PATCH, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
295         EdgePayload payload = EdgePayload.fromJson(content);
296         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
297           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
298         }
299         if (payload.getId() != null && !payload.getId().equals(id)) {
300           throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
301         }
302
303         String result = graphDataService.patchEdge(version, id, type, payload);
304         response = Response.status(Status.OK).entity(result).type(mediaType).build();
305       } else {
306         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
307       }
308     } catch (CrudException ce) {
309       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
310     } catch (Exception e) {
311       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
312     }
313
314     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
315     return response;
316   }
317
318   @PUT
319   @Path("/{version}/{type}/{id}")
320   @Consumes({MediaType.APPLICATION_JSON})
321   @Produces({MediaType.APPLICATION_JSON})
322   public Response updateVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
323                                @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
324                                @Context UriInfo uriInfo, @Context HttpServletRequest req) {
325
326     LoggingUtil.initMdcContext(req, headers);
327
328     logger.debug("Incoming request..." + content);
329     Response response = null;
330
331
332     try {
333       if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
334         VertexPayload payload = VertexPayload.fromJson(content);
335         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
336           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
337         }
338         if (payload.getId() != null && !payload.getId().equals(id)) {
339           throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
340         }
341
342         String result;
343
344         payload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, false));
345
346         if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null
347             && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
348           result = graphDataService.patchVertex(version, id, type, payload);
349         } else {
350
351           result = graphDataService.updateVertex(version, id, type, payload);
352         }
353         response = Response.status(Status.OK).entity(result).type(mediaType).build();
354       } else {
355         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
356       }
357     } catch (CrudException ce) {
358       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
359     } catch (Exception e) {
360       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
361     }
362
363     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
364     return response;
365   }
366
367   @PATCH
368   @Path("/{version}/{type}/{id}")
369   @Consumes({"application/merge-patch+json"})
370   @Produces({MediaType.APPLICATION_JSON})
371   public Response patchVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
372                               @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
373                               @Context UriInfo uriInfo, @Context HttpServletRequest req) {
374
375     LoggingUtil.initMdcContext(req, headers);
376
377     logger.debug("Incoming request..." + content);
378     Response response = null;
379
380     try {
381       if (validateRequest(req, uri, content, Action.PATCH, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
382         VertexPayload payload = VertexPayload.fromJson(content);
383         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
384           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
385         }
386         if (payload.getId() != null && !payload.getId().equals(id)) {
387           throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
388         }
389
390         payload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, false));
391
392         String result = graphDataService.patchVertex(version, id, type, payload);
393         response = Response.status(Status.OK).entity(result).type(mediaType).build();
394       } else {
395         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
396       }
397     } catch (CrudException ce) {
398       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
399     } catch (Exception e) {
400       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
401     }
402
403     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
404     return response;
405   }
406
407   @POST
408   @Path("/{version}/{type}/")
409   @Consumes({MediaType.APPLICATION_JSON})
410   @Produces({MediaType.APPLICATION_JSON})
411   public Response addVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
412                             @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
413                             @Context HttpServletRequest req) {
414
415     LoggingUtil.initMdcContext(req, headers);
416
417     logger.debug("Incoming request..." + content);
418     Response response = null;
419
420
421     try {
422       if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
423         VertexPayload payload = VertexPayload.fromJson(content);
424         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
425           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
426         }
427         if (payload.getId() != null) {
428           throw new CrudException("ID specified , use Http PUT to update Vertex", Status.BAD_REQUEST);
429         }
430
431         if (payload.getType() != null && !payload.getType().equals(type)) {
432           throw new CrudException("Vertex Type mismatch", Status.BAD_REQUEST);
433         }
434
435         payload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, true));
436
437         String result = graphDataService.addVertex(version, type, payload);
438         response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
439       } else {
440         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
441       }
442     } catch (CrudException ce) {
443       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
444     } catch (Exception e) {
445       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
446     }
447
448     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
449     return response;
450   }
451
452   private void validateBulkPayload(BulkPayload payload) throws CrudException {
453     List<String> vertices = new ArrayList<String>();
454     List<String> edges = new ArrayList<String>();
455
456     for (JsonElement v : payload.getObjects()) {
457       List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
458           v.getAsJsonObject().entrySet());
459
460       if (entries.size() != 2) {
461         throw new CrudException("", Status.BAD_REQUEST);
462       }
463       Map.Entry<String, JsonElement> opr = entries.get(0);
464       Map.Entry<String, JsonElement> item = entries.get(1);
465
466       if (vertices.contains(item.getKey())) {
467         throw new CrudException("duplicate vertex in payload: " + item.getKey(), Status.BAD_REQUEST);
468       }
469       VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString());
470       if (vertexPayload.getType() == null) {
471         throw new CrudException("Vertex Type cannot be null for: " + item.getKey(), Status.BAD_REQUEST);
472       }
473
474       if (!opr.getKey().equalsIgnoreCase("operation")) {
475         throw new CrudException("operation missing in item: " + item.getKey(), Status.BAD_REQUEST);
476       }
477
478       if (!opr.getValue().getAsString().equalsIgnoreCase("add")
479           && !opr.getValue().getAsString().equalsIgnoreCase("modify")
480           && !opr.getValue().getAsString().equalsIgnoreCase("patch")
481           && !opr.getValue().getAsString().equalsIgnoreCase("delete")) {
482         throw new CrudException("Invalid operation at item: " + item.getKey(), Status.BAD_REQUEST);
483       }
484       // check if ID is populate for modify/patch/delete operation
485       if ((opr.getValue().getAsString().equalsIgnoreCase("modify")
486           || opr.getValue().getAsString().equalsIgnoreCase("patch")
487           || opr.getValue().getAsString().equalsIgnoreCase("delete")) && (vertexPayload.getId() == null)) {
488
489         throw new CrudException("Mising ID at item: " + item.getKey(), Status.BAD_REQUEST);
490
491       }
492
493       vertices.add(item.getKey());
494     }
495
496     for (JsonElement v : payload.getRelationships()) {
497       List<Map.Entry<String, JsonElement>> entries = new ArrayList<Map.Entry<String, JsonElement>>(
498           v.getAsJsonObject().entrySet());
499
500       if (entries.size() != 2) {
501         throw new CrudException("", Status.BAD_REQUEST);
502       }
503       Map.Entry<String, JsonElement> opr = entries.get(0);
504       Map.Entry<String, JsonElement> item = entries.get(1);
505
506       if (edges.contains(item.getKey())) {
507         throw new CrudException("duplicate Edge in payload: " + item.getKey(), Status.BAD_REQUEST);
508       }
509
510       EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString());
511
512       if (edgePayload.getType() == null) {
513         throw new CrudException("Edge Type cannot be null for: " + item.getKey(), Status.BAD_REQUEST);
514       }
515
516       if (!opr.getKey().equalsIgnoreCase("operation")) {
517         throw new CrudException("operation missing in item: " + item.getKey(), Status.BAD_REQUEST);
518       }
519
520       if (!opr.getValue().getAsString().equalsIgnoreCase("add")
521           && !opr.getValue().getAsString().equalsIgnoreCase("modify")
522           && !opr.getValue().getAsString().equalsIgnoreCase("patch")
523           && !opr.getValue().getAsString().equalsIgnoreCase("delete")) {
524         throw new CrudException("Invalid operation at item: " + item.getKey(), Status.BAD_REQUEST);
525       }
526       // check if ID is populate for modify/patch/delete operation
527       if ((edgePayload.getId() == null) && (opr.getValue().getAsString().equalsIgnoreCase("modify")
528           || opr.getValue().getAsString().equalsIgnoreCase("patch")
529           || opr.getValue().getAsString().equalsIgnoreCase("delete"))) {
530
531         throw new CrudException("Mising ID at item: " + item.getKey(), Status.BAD_REQUEST);
532
533       }
534       if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
535         if (edgePayload.getSource() == null || edgePayload.getTarget() == null) {
536           throw new CrudException("Source/Target cannot be null for edge: " + item.getKey(), Status.BAD_REQUEST);
537         }
538         if (edgePayload.getSource().startsWith("$") && !vertices.contains(edgePayload.getSource().substring(1))) {
539           throw new CrudException(
540               "Source Vertex " + edgePayload.getSource().substring(1) + " not found for Edge: " + item.getKey(),
541               Status.BAD_REQUEST);
542         }
543
544         if (edgePayload.getTarget().startsWith("$") && !vertices.contains(edgePayload.getTarget().substring(1))) {
545           throw new CrudException(
546               "Target Vertex " + edgePayload.getSource().substring(1) + " not found for Edge: " + item.getKey(),
547               Status.BAD_REQUEST);
548         }
549       }
550       edges.add(item.getKey());
551
552     }
553
554   }
555
556   @POST
557   @Path("/{version}/bulk/")
558   @Consumes({MediaType.APPLICATION_JSON})
559   @Produces({MediaType.APPLICATION_JSON})
560   public Response addBulk(String content, @PathParam("version") String version, @PathParam("type") String type,
561                           @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
562                           @Context HttpServletRequest req) {
563
564     LoggingUtil.initMdcContext(req, headers);
565
566     logger.debug("Incoming request..." + content);
567     Response response = null;
568
569
570     try {
571       if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
572         BulkPayload payload = BulkPayload.fromJson(content);
573         if ((payload.getObjects() == null && payload.getRelationships() == null)
574             || (payload.getObjects() != null && payload.getObjects().isEmpty() && payload.getRelationships() != null
575             && payload.getRelationships().isEmpty())) {
576           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
577         }
578
579         validateBulkPayload(payload);
580         String result = graphDataService.addBulk(version, payload, headers);
581         response = Response.status(Status.OK).entity(result).type(mediaType).build();
582       } else {
583         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
584       }
585     } catch (CrudException ce) {
586       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
587     } catch (Exception e) {
588       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
589     }
590
591     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
592     return response;
593   }
594
595   @POST
596   @Path("/{version}/")
597   @Consumes({MediaType.APPLICATION_JSON})
598   @Produces({MediaType.APPLICATION_JSON})
599   public Response addVertex(String content, @PathParam("version") String version, @PathParam("uri") @Encoded String uri,
600                             @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
601
602     LoggingUtil.initMdcContext(req, headers);
603
604     logger.debug("Incoming request..." + content);
605     Response response = null;
606
607     try {
608
609       if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
610         VertexPayload payload = VertexPayload.fromJson(content);
611         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
612           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
613         }
614         if (payload.getId() != null) {
615           throw new CrudException("ID specified , use Http PUT to update Vertex", Status.BAD_REQUEST);
616         }
617
618         if (payload.getType() == null || payload.getType().isEmpty()) {
619           throw new CrudException("Missing Vertex Type ", Status.BAD_REQUEST);
620         }
621
622         payload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, true));
623
624         String result = graphDataService.addVertex(version, payload.getType(), payload);
625         response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
626       } else {
627         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
628       }
629     } catch (CrudException ce) {
630       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
631     } catch (Exception e) {
632       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
633     }
634
635     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
636     return response;
637   }
638
639   @POST
640   @Path("/relationships/{version}/{type}/")
641   @Consumes({MediaType.APPLICATION_JSON})
642   @Produces({MediaType.APPLICATION_JSON})
643   public Response addEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
644                           @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
645                           @Context HttpServletRequest req) {
646
647     LoggingUtil.initMdcContext(req, headers);
648
649     logger.debug("Incoming request..." + content);
650     Response response = null;
651
652
653     try {
654       if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
655         EdgePayload payload = EdgePayload.fromJson(content);
656         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
657           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
658         }
659         if (payload.getId() != null) {
660           throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
661         }
662
663         if (payload.getType() != null && !payload.getType().equals(type)) {
664           throw new CrudException("Edge Type mismatch", Status.BAD_REQUEST);
665         }
666         String result = graphDataService.addEdge(version, type, payload);
667         response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
668       } else {
669         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
670       }
671     } catch (CrudException ce) {
672       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
673     } catch (Exception e) {
674       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
675     }
676
677     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
678     return response;
679   }
680
681   @POST
682   @Path("/relationships/{version}/")
683   @Consumes({MediaType.APPLICATION_JSON})
684   @Produces({MediaType.APPLICATION_JSON})
685   public Response addEdge(String content, @PathParam("version") String version, @PathParam("uri") @Encoded String uri,
686                           @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
687
688     LoggingUtil.initMdcContext(req, headers);
689
690     logger.debug("Incoming request..." + content);
691     Response response = null;
692
693
694     try {
695       if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
696         EdgePayload payload = EdgePayload.fromJson(content);
697         if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
698           throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
699         }
700         if (payload.getId() != null) {
701           throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
702         }
703
704         if (payload.getType() == null || payload.getType().isEmpty()) {
705           throw new CrudException("Missing Edge Type ", Status.BAD_REQUEST);
706         }
707         String result = graphDataService.addEdge(version, payload.getType(), payload);
708
709         response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
710       } else {
711         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
712       }
713     } catch (CrudException ce) {
714       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
715     } catch (Exception e) {
716       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
717     }
718
719     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
720     return response;
721   }
722
723   @DELETE
724   @Path("/{version}/{type}/{id}")
725   @Consumes({MediaType.APPLICATION_JSON})
726   @Produces({MediaType.APPLICATION_JSON})
727   public Response deleteVertex(String content, @PathParam("version") String version, @PathParam("type") String type,
728                                @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
729                                @Context UriInfo uriInfo, @Context HttpServletRequest req) {
730
731     LoggingUtil.initMdcContext(req, headers);
732
733     logger.debug("Incoming request..." + content);
734     Response response = null;
735
736
737     try {
738       if (validateRequest(req, uri, content, Action.DELETE, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
739         String result = graphDataService.deleteVertex(version, id, type);
740         response = Response.status(Status.OK).entity(result).type(mediaType).build();
741       } else {
742         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
743       }
744     } catch (CrudException ce) {
745       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
746     } catch (Exception e) {
747       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
748     }
749
750     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
751     return response;
752   }
753
754   @DELETE
755   @Path("/relationships/{version}/{type}/{id}")
756   @Consumes({MediaType.APPLICATION_JSON})
757   @Produces({MediaType.APPLICATION_JSON})
758   public Response deleteEdge(String content, @PathParam("version") String version, @PathParam("type") String type,
759                              @PathParam("id") String id, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers,
760                              @Context UriInfo uriInfo, @Context HttpServletRequest req) {
761
762     LoggingUtil.initMdcContext(req, headers);
763
764     logger.debug("Incoming request..." + content);
765     Response response = null;
766
767     try {
768       if (validateRequest(req, uri, content, Action.DELETE, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
769         String result = graphDataService.deleteEdge(version, id, type);
770         response = Response.status(Status.OK).entity(result).type(mediaType).build();
771       } else {
772         response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON).build();
773       }
774     } catch (CrudException ce) {
775       response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
776     } catch (Exception e) {
777       response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
778     }
779
780     LoggingUtil.logRestRequest(logger, auditLogger, req, response);
781     return response;
782   }
783
784   protected boolean validateRequest(HttpServletRequest req, String uri, String content, Action action,
785                                     String authPolicyFunctionName, HttpHeaders headers) throws CrudException {
786     boolean isValid = false;
787     try {
788       String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite");
789       String authUser = null;
790       if (cipherSuite != null) {
791         X509Certificate[] certChain = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
792         X509Certificate clientCert = certChain[0];
793         X500Principal subjectDn = clientCert.getSubjectX500Principal();
794         authUser = subjectDn.toString();
795       }
796       isValid = this.auth.validateRequest(authUser.toLowerCase(), action.toString() + ":" + authPolicyFunctionName);
797     } catch (Exception e) {
798       logResult(action, uri, e);
799       return false;
800     }
801
802     String sourceOfTruth = null;
803     if (headers.getRequestHeaders().containsKey("X-FromAppId")) {
804       sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
805     }
806
807     if (sourceOfTruth == null || sourceOfTruth.trim() == "") {
808       throw new CrudException("Invalid request, Missing X-FromAppId header", Status.BAD_REQUEST);
809     }
810
811     return isValid;
812   }
813
814   void logResult(Action op, String uri, Exception e) {
815
816     logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL, op.toString(), uri, e.getStackTrace().toString());
817
818     // Clear the MDC context so that no other transaction inadvertently
819     // uses our transaction id.
820     MDC.clear();
821   }
822 }