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