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