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