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