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