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