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