Remove Multiplicity feature
[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.Arrays;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.security.auth.x500.X500Principal;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.ws.rs.Consumes;
34 import javax.ws.rs.DELETE;
35 import javax.ws.rs.Encoded;
36 import javax.ws.rs.GET;
37 import javax.ws.rs.POST;
38 import javax.ws.rs.PUT;
39 import javax.ws.rs.Path;
40 import javax.ws.rs.PathParam;
41 import javax.ws.rs.Produces;
42 import javax.ws.rs.core.Context;
43 import javax.ws.rs.core.EntityTag;
44 import javax.ws.rs.core.HttpHeaders;
45 import javax.ws.rs.core.MediaType;
46 import javax.ws.rs.core.Response;
47 import javax.ws.rs.core.Response.ResponseBuilder;
48 import javax.ws.rs.core.Response.Status;
49 import javax.ws.rs.core.UriInfo;
50
51 import org.apache.commons.lang3.tuple.ImmutablePair;
52 import org.apache.cxf.jaxrs.ext.PATCH;
53 import org.onap.aai.cl.api.Logger;
54 import org.onap.aai.cl.eelf.LoggerFactory;
55 import org.onap.aaiauth.auth.Auth;
56 import org.onap.crud.exception.CrudException;
57 import org.onap.crud.logging.CrudServiceMsgs;
58 import org.onap.crud.logging.LoggingUtil;
59 import org.onap.crud.util.CrudProperties;
60 import org.onap.crud.util.CrudServiceConstants;
61 import org.onap.crud.util.CrudServiceUtil;
62 import org.slf4j.MDC;
63
64 import com.google.gson.JsonElement;
65
66 import io.swagger.annotations.ApiImplicitParam;
67 import io.swagger.annotations.ApiImplicitParams;
68 import io.swagger.annotations.ApiOperation;
69 import io.swagger.annotations.ApiParam;
70 import io.swagger.annotations.ApiResponse;
71 import io.swagger.annotations.ApiResponses;
72
73 @Path("/inventory")
74 public class CrudRestService {
75
76     private AbstractGraphDataService graphDataService;
77     Logger logger = LoggerFactory.getInstance().getLogger(CrudRestService.class.getName());
78     Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(CrudRestService.class.getName());
79     private Auth auth;
80     private boolean authorizationEnabled;
81
82     private String mediaType = MediaType.APPLICATION_JSON;
83     public static final String HTTP_PATCH_METHOD_OVERRIDE = "X-HTTP-Method-Override";
84     public static final String TRANSACTIONID_HEADER = "X-TransactionId";
85
86     public CrudRestService(AbstractGraphDataService graphDataService) throws Exception {
87         this.graphDataService = graphDataService;
88         
89         this.authorizationEnabled = Boolean.parseBoolean(
90                 CrudProperties.get(CrudServiceConstants.CRD_AUTHORIZATION_ENABLED, "true"));
91
92         this.auth = null;
93         if (this.authorizationEnabled) {
94             this.auth = new Auth(CrudServiceConstants.CRD_AUTH_FILE);
95         }        
96     }
97
98     // For unit testing
99     public CrudRestService(AbstractGraphDataService graphDataService, Auth auth) throws Exception {
100         this.graphDataService = graphDataService;
101         this.auth = auth;
102     }
103
104     public enum Action {
105         POST, GET, PUT, DELETE, PATCH
106     }
107
108     public void startup() {
109
110     }
111     
112     @ApiOperation(value = "Get Vertex" , notes="For example : https://<host>:9520/services/inventory/v11/pserver/<id>")
113     @ApiResponses({    
114       @ApiResponse(code = 200, message = "Success"),
115       @ApiResponse(code = 403, message = "Forbidden"),    
116       @ApiResponse(code = 404, message = "Not Found"),
117       @ApiResponse(code = 500, message = "Internal Server Error") })
118     @ApiImplicitParams({
119       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
120       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
121     })
122     @GET
123     @Path("/{version}/{type}/{id}")
124     @Consumes({MediaType.APPLICATION_JSON})
125     @Produces({MediaType.APPLICATION_JSON})
126     public Response getVertex(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
127             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
128             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
129
130         LoggingUtil.initMdcContext(req, headers);
131         logger.debug("Incoming request..." + content);
132
133         ResponseBuilder responseBuilder;
134         Map<String, String> params = addParams(uriInfo, false, type, version);
135
136         try {
137             if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
138                 ImmutablePair<EntityTag, String> result = graphDataService.getVertex(version, id, type, params);
139                 responseBuilder =
140                         Response.status(Status.OK).entity(result.getValue()).tag(result.getKey()).type(mediaType);
141             } else {
142                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
143             }
144         } catch (CrudException ce) {
145             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
146         } catch (Exception e) {
147             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
148
149         }
150
151         setTxIdOnResponseHeader(headers, responseBuilder);
152
153         Response response = responseBuilder.build();
154         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
155         return response;
156     }
157
158     @ApiOperation(value = "Get Vertices" , notes="For example : https://<host>:9520/services/inventory/v11/pserver/")
159     @ApiResponses({    
160       @ApiResponse(code = 200, message = "Success"),
161       @ApiResponse(code = 403, message = "Forbidden"),    
162       @ApiResponse(code = 404, message = "Not Found"),
163       @ApiResponse(code = 500, message = "Internal Server Error") })
164     @ApiImplicitParams({
165       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),    
166       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
167     })
168     @GET
169     @Path("/{version}/{type}/")
170     @Consumes({MediaType.APPLICATION_JSON})
171     @Produces({MediaType.APPLICATION_JSON})
172     public Response getVertices(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
173             @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
174             @Context HttpServletRequest req) {
175
176         LoggingUtil.initMdcContext(req, headers);
177         logger.debug("Incoming request..." + content);
178
179         ResponseBuilder responseBuilder;
180         try {
181             if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
182                 String propertiesKey = CrudProperties.get(CrudServiceConstants.CRD_COLLECTION_PROPERTIES_KEY);
183                 Map<String, String> filter = addParams(uriInfo, true, type, version);
184
185                 HashSet<String> properties;
186                 if (uriInfo.getQueryParameters().containsKey(propertiesKey)) {
187                     properties = new HashSet<>(uriInfo.getQueryParameters().get(propertiesKey));
188                 } else {
189                     properties = new HashSet<>();
190                 }
191
192                 ImmutablePair<EntityTag, String> result =
193                         graphDataService.getVertices(version, type, filter, properties);
194                 responseBuilder =
195                         Response.status(Status.OK).entity(result.getValue()).tag(result.getKey()).type(mediaType);
196             } else {
197                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
198             }
199         } catch (CrudException ce) {
200             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
201         } catch (Exception e) {
202             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
203
204         }
205
206         setTxIdOnResponseHeader(headers, responseBuilder);
207
208         Response response = responseBuilder.build();
209         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
210         return response;
211     }
212
213     @ApiOperation(value = "Get Edge" , notes="For example : https://<host>:9520/services/inventory/relationships/v11/tosca.relationships.HostedOn/<id>")
214     @ApiResponses({    
215       @ApiResponse(code = 200, message = "Success"),
216       @ApiResponse(code = 403, message = "Forbidden"),    
217       @ApiResponse(code = 404, message = "Not Found"),
218       @ApiResponse(code = 500, message = "Internal Server Error") })
219     @ApiImplicitParams({
220       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
221       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
222     })
223     @GET
224     @Path("/relationships/{version}/{type}/{id}")
225     @Consumes({MediaType.APPLICATION_JSON})
226     @Produces({MediaType.APPLICATION_JSON})
227     public Response getEdge(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
228             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
229             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
230
231         LoggingUtil.initMdcContext(req, headers);
232         logger.debug("Incoming request..." + content);
233
234         ResponseBuilder responseBuilder;
235         Map<String, String> params = addParams(uriInfo, false, type, version);
236
237         try {
238             if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
239
240                 ImmutablePair<EntityTag, String> result = graphDataService.getEdge(version, id, type, params);
241                 responseBuilder =
242                         Response.status(Status.OK).entity(result.getValue()).tag(result.getKey()).type(mediaType);
243             } else {
244                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
245             }
246         } catch (CrudException ce) {
247             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
248         } catch (Exception e) {
249             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
250         }
251
252         setTxIdOnResponseHeader(headers, responseBuilder);
253
254         Response response = responseBuilder.build();
255         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
256         return response;
257     }
258
259     @ApiOperation(value = "Get Edges" , notes="For example : https://<host>:9520/services/inventory/relationships/v11/tosca.relationships.HostedOn/")
260     @ApiResponses({    
261       @ApiResponse(code = 200, message = "Success"),
262       @ApiResponse(code = 403, message = "Forbidden"),    
263       @ApiResponse(code = 404, message = "Not Found"),
264       @ApiResponse(code = 500, message = "Internal Server Error") })
265     @ApiImplicitParams({
266       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
267       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
268     })
269     @GET
270     @Path("/relationships/{version}/{type}/")
271     @Consumes({MediaType.APPLICATION_JSON})
272     @Produces({MediaType.APPLICATION_JSON})
273     public Response getEdges(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
274             @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
275             @Context HttpServletRequest req) {
276
277         LoggingUtil.initMdcContext(req, headers);
278         logger.debug("Incoming request..." + content);
279
280         ResponseBuilder responseBuilder;
281         Map<String, String> filter = addParams(uriInfo, true, type, version);
282
283         try {
284             if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
285                 ImmutablePair<EntityTag, String> result = graphDataService.getEdges(version, type, filter);
286                 responseBuilder =
287                         Response.status(Status.OK).entity(result.getValue()).tag(result.getKey()).type(mediaType);
288             } else {
289                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
290             }
291         } catch (CrudException ce) {
292             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
293         } catch (Exception e) {
294             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
295         }
296
297         setTxIdOnResponseHeader(headers, responseBuilder);
298
299         Response response = responseBuilder.build();
300         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
301         return response;
302     }
303
304     @ApiOperation(value = "Update Edge" , notes = "# Payload \n"
305         + "{  \r\n" + 
306         "   \"properties\":{  \r\n" + 
307         "        \"prop1\" : \"value\",\r\n" + 
308         "        \"prop2\" :\"value\",\r\n" +  
309         "    ..}\r\n" + 
310         " }")
311     @ApiResponses({    
312       @ApiResponse(code = 200, message = "Success"),
313       @ApiResponse(code = 403, message = "Forbidden"),    
314       @ApiResponse(code = 404, message = "Not Found"),
315       @ApiResponse(code = 400, message = "Bad Request"),
316       @ApiResponse(code = 500, message = "Internal Server Error") })
317     @ApiImplicitParams({
318       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
319       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
320     })
321     @PUT
322     @Path("/relationships/{version}/{type}/{id}")
323     @Consumes({MediaType.APPLICATION_JSON})
324     @Produces({MediaType.APPLICATION_JSON})
325     public Response updateEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
326             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
327             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
328
329         LoggingUtil.initMdcContext(req, headers);
330         logger.debug("Incoming request..." + content);
331
332         ResponseBuilder responseBuilder;
333
334         try {
335             if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
336                 EdgePayload payload = EdgePayload.fromJson(content);
337                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
338                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
339                 }
340                 if (payload.getId() != null && !payload.getId().equals(id)) {
341                     throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
342                 }
343                 ImmutablePair<EntityTag, String> result;
344                 if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null
345                         && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
346                     result = graphDataService.patchEdge(version, id, type, payload);
347                     responseBuilder =
348                             Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey());
349                 } else {
350                     result = graphDataService.updateEdge(version, id, type, payload);
351                     responseBuilder =
352                             Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey());
353                 }
354
355             } else {
356                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
357             }
358         } catch (CrudException ce) {
359             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
360         } catch (Exception e) {
361             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
362         }
363
364         setTxIdOnResponseHeader(headers, responseBuilder);
365
366         Response response = responseBuilder.build();
367         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
368         return response;
369     }
370
371     @ApiOperation(value = "Patch Edge" , notes = "# Payload \n"
372         + "{  \r\n" + 
373         "   \"properties\":{  \r\n" + 
374         "        \"prop1\" : \"value\",\r\n" + 
375         "        \"prop2\" :\"value\",\r\n" +  
376         "    ..}\r\n" + 
377         " }")
378     @ApiResponses({    
379       @ApiResponse(code = 200, message = "Success"),
380       @ApiResponse(code = 403, message = "Forbidden"), 
381       @ApiResponse(code = 400, message = "Bad Request"),
382       @ApiResponse(code = 404, message = "Not Found"),
383       @ApiResponse(code = 500, message = "Internal Server Error") })
384     @ApiImplicitParams({
385       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
386       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
387     })
388     @PATCH
389     @Path("/relationships/{version}/{type}/{id}")
390     @Consumes({"application/merge-patch+json"})
391     @Produces({MediaType.APPLICATION_JSON})
392     public Response patchEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
393             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
394             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
395
396         LoggingUtil.initMdcContext(req, headers);
397         logger.debug("Incoming request..." + content);
398
399         ResponseBuilder responseBuilder;
400
401         try {
402             if (validateRequest(req, uri, content, Action.PATCH, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
403                 EdgePayload payload = EdgePayload.fromJson(content);
404                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
405                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
406                 }
407                 if (payload.getId() != null && !payload.getId().equals(id)) {
408                     throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
409                 }
410
411                 ImmutablePair<EntityTag, String> result = graphDataService.patchEdge(version, id, type, payload);
412                 responseBuilder =
413                         Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey());
414             } else {
415                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
416             }
417         } catch (CrudException ce) {
418             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
419         } catch (Exception e) {
420             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
421         }
422
423         setTxIdOnResponseHeader(headers, responseBuilder);
424
425         Response response = responseBuilder.build();
426         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
427         return response;
428     }
429
430     @ApiOperation(value = "Update Vertex" , notes = "# Payload \n"
431         + "{\r\n" + 
432         "   \"type\" :\"vertex type from oxm like comcast.nodes.sdwan.vpn\",\r\n" + 
433         "    \"properties\": {\r\n" + 
434         "        \"prop1\" : \"value\",\r\n" + 
435         "        \"prop2\" :\"value\",\r\n" +          
436         "    ..}\r\n" + 
437         " }")
438     @ApiResponses({    
439       @ApiResponse(code = 200, message = "Success"),
440       @ApiResponse(code = 403, message = "Forbidden"), 
441       @ApiResponse(code = 400, message = "Bad Request"),
442       @ApiResponse(code = 404, message = "Not Found"),
443       @ApiResponse(code = 500, message = "Internal Server Error") })
444     @ApiImplicitParams({
445       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
446       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
447     })
448     @PUT
449     @Path("/{version}/{type}/{id}")
450     @Consumes({MediaType.APPLICATION_JSON})
451     @Produces({MediaType.APPLICATION_JSON})
452     public Response updateVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
453             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
454             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
455
456         LoggingUtil.initMdcContext(req, headers);
457         logger.debug("Incoming request..." + content);
458
459         ResponseBuilder responseBuilder;
460
461         try {
462             if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
463                 VertexPayload payload = VertexPayload.fromJson(content);
464                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
465                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
466                 }
467                 if (payload.getId() != null && !payload.getId().equals(id)) {
468                     throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
469                 }
470
471                 payload.setProperties(
472                         CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, false));
473
474                 ImmutablePair<EntityTag, String> result;
475                 if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null
476                         && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
477                     result = graphDataService.patchVertex(version, id, type, payload);
478                     responseBuilder =
479                             Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey());
480                 } else {
481                     result = graphDataService.updateVertex(version, id, type, payload);
482                     responseBuilder =
483                             Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey());
484                 }
485
486             } else {
487                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
488             }
489         } catch (CrudException ce) {
490             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
491         } catch (Exception e) {
492             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
493         }
494
495         setTxIdOnResponseHeader(headers, responseBuilder);
496
497         Response response = responseBuilder.build();
498         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
499         return response;
500     }
501
502     @ApiOperation(value = "Patch Vertex" , notes = "# Payload \n"
503         + "{\r\n" + 
504         "   \"type\" :\"vertex type from oxm like comcast.nodes.sdwan.vpn\",\r\n" + 
505         "    \"properties\": {\r\n" + 
506         "        \"prop1\" : \"true\",\r\n" + 
507         "        \"prop2\" :\"name1\",\r\n" +         
508         "    ..}\r\n" + 
509         " }")
510     @ApiResponses({    
511       @ApiResponse(code = 200, message = "Success"),
512       @ApiResponse(code = 403, message = "Forbidden"), 
513       @ApiResponse(code = 400, message = "Bad Request"),
514       @ApiResponse(code = 404, message = "Not Found"),
515       @ApiResponse(code = 500, message = "Internal Server Error") })
516     @ApiImplicitParams({
517       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
518       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
519     })
520     @PATCH
521     @Path("/{version}/{type}/{id}")
522     @Consumes({"application/merge-patch+json"})
523     @Produces({MediaType.APPLICATION_JSON})
524     public Response patchVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
525             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
526             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
527
528         LoggingUtil.initMdcContext(req, headers);
529         logger.debug("Incoming request..." + content);
530
531         ResponseBuilder responseBuilder;
532
533         try {
534             if (validateRequest(req, uri, content, Action.PATCH, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
535                 VertexPayload payload = VertexPayload.fromJson(content);
536                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
537                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
538                 }
539                 if (payload.getId() != null && !payload.getId().equals(id)) {
540                     throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
541                 }
542
543                 payload.setProperties(
544                         CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, false));
545
546                 ImmutablePair<EntityTag, String> result = graphDataService.patchVertex(version, id, type, payload);
547                 responseBuilder =
548                         Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey());
549             } else {
550                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
551             }
552         } catch (CrudException ce) {
553             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
554         } catch (Exception e) {
555             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
556         }
557
558         setTxIdOnResponseHeader(headers, responseBuilder);
559
560         Response response = responseBuilder.build();
561         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
562         return response;
563     }
564
565     @ApiOperation(value = "Create Vertex" , notes = "# Payload \n"
566         + "{\r\n" +      
567         "    \"properties\": {\r\n" + 
568         "        \"prop1\" : \"value\",\r\n" + 
569         "        \"prop2\" :\"value\",\r\n" +         
570         "    ..}\r\n" + 
571         " }")
572     @ApiResponses({    
573       @ApiResponse(code = 201, message = "Created"),
574       @ApiResponse(code = 403, message = "Forbidden"), 
575       @ApiResponse(code = 400, message = "Bad Request"),
576       @ApiResponse(code = 404, message = "Not Found"),
577       @ApiResponse(code = 500, message = "Internal Server Error") })
578     @ApiImplicitParams({
579       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
580       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
581     })
582     @POST
583     @Path("/{version}/{type}/")
584     @Consumes({MediaType.APPLICATION_JSON})
585     @Produces({MediaType.APPLICATION_JSON})
586     public Response addVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
587             @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
588             @Context HttpServletRequest req) {
589
590         LoggingUtil.initMdcContext(req, headers);
591         logger.debug("Incoming request..." + content);
592
593         ResponseBuilder responseBuilder;
594
595         try {
596             if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
597                 VertexPayload payload = VertexPayload.fromJson(content);
598                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
599                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
600                 }
601                 if (payload.getId() != null) {
602                     throw new CrudException("ID specified , use Http PUT to update Vertex", Status.BAD_REQUEST);
603                 }
604
605                 if (payload.getType() != null && !payload.getType().equals(type)) {
606                     throw new CrudException("Vertex Type mismatch", Status.BAD_REQUEST);
607                 }
608
609                 payload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, true));
610
611                 ImmutablePair<EntityTag, String> result = graphDataService.addVertex(version, type, payload);
612                 responseBuilder =
613                         Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType);
614             } else {
615                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
616             }
617         } catch (CrudException ce) {
618             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
619         } catch (Exception e) {
620             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
621         }
622
623         setTxIdOnResponseHeader(headers, responseBuilder);
624
625         Response response = responseBuilder.build();
626         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
627         return response;
628     }
629
630     private void validateBulkPayload(BulkPayload payload) throws CrudException {
631         List<String> vertices = new ArrayList<String>();
632         List<String> edges = new ArrayList<String>();
633
634         for (JsonElement v : payload.getObjects()) {
635             List<Map.Entry<String, JsonElement>> entries =
636                     new ArrayList<Map.Entry<String, JsonElement>>(v.getAsJsonObject().entrySet());
637
638             if (entries.size() != 2) {
639                 throw new CrudException("", Status.BAD_REQUEST);
640             }
641             Map.Entry<String, JsonElement> opr = entries.get(0);
642             Map.Entry<String, JsonElement> item = entries.get(1);
643
644             if (vertices.contains(item.getKey())) {
645                 throw new CrudException("duplicate vertex in payload: " + item.getKey(), Status.BAD_REQUEST);
646             }
647             VertexPayload vertexPayload = VertexPayload.fromJson(item.getValue().getAsJsonObject().toString());
648             if (vertexPayload.getType() == null) {
649                 throw new CrudException("Vertex Type cannot be null for: " + item.getKey(), Status.BAD_REQUEST);
650             }
651
652             if (!opr.getKey().equalsIgnoreCase("operation")) {
653                 throw new CrudException("operation missing in item: " + item.getKey(), Status.BAD_REQUEST);
654             }
655
656             if (!opr.getValue().getAsString().equalsIgnoreCase("add")
657                     && !opr.getValue().getAsString().equalsIgnoreCase("modify")
658                     && !opr.getValue().getAsString().equalsIgnoreCase("patch")
659                     && !opr.getValue().getAsString().equalsIgnoreCase("delete")) {
660                 throw new CrudException("Invalid operation at item: " + item.getKey(), Status.BAD_REQUEST);
661             }
662             // check if ID is populate for modify/patch/delete operation
663             if ((opr.getValue().getAsString().equalsIgnoreCase("modify")
664                     || opr.getValue().getAsString().equalsIgnoreCase("patch")
665                     || opr.getValue().getAsString().equalsIgnoreCase("delete")) && (vertexPayload.getId() == null)) {
666
667                 throw new CrudException("Mising ID at item: " + item.getKey(), Status.BAD_REQUEST);
668
669             }
670
671             vertices.add(item.getKey());
672         }
673
674         for (JsonElement v : payload.getRelationships()) {
675             List<Map.Entry<String, JsonElement>> entries =
676                     new ArrayList<Map.Entry<String, JsonElement>>(v.getAsJsonObject().entrySet());
677
678             if (entries.size() != 2) {
679                 throw new CrudException("", Status.BAD_REQUEST);
680             }
681             Map.Entry<String, JsonElement> opr = entries.get(0);
682             Map.Entry<String, JsonElement> item = entries.get(1);
683
684             if (edges.contains(item.getKey())) {
685                 throw new CrudException("duplicate Edge in payload: " + item.getKey(), Status.BAD_REQUEST);
686             }
687
688             EdgePayload edgePayload = EdgePayload.fromJson(item.getValue().getAsJsonObject().toString());
689
690             if (!opr.getKey().equalsIgnoreCase("operation")) {
691                 throw new CrudException("operation missing in item: " + item.getKey(), Status.BAD_REQUEST);
692             }
693
694             if (!opr.getValue().getAsString().equalsIgnoreCase("add")
695                     && !opr.getValue().getAsString().equalsIgnoreCase("modify")
696                     && !opr.getValue().getAsString().equalsIgnoreCase("patch")
697                     && !opr.getValue().getAsString().equalsIgnoreCase("delete")) {
698                 throw new CrudException("Invalid operation at item: " + item.getKey(), Status.BAD_REQUEST);
699             }
700             // check if ID is populate for modify/patch/delete operation
701             if ((edgePayload.getId() == null) && (opr.getValue().getAsString().equalsIgnoreCase("modify")
702                     || opr.getValue().getAsString().equalsIgnoreCase("patch")
703                     || opr.getValue().getAsString().equalsIgnoreCase("delete"))) {
704
705                 throw new CrudException("Mising ID at item: " + item.getKey(), Status.BAD_REQUEST);
706
707             }
708             if (opr.getValue().getAsString().equalsIgnoreCase("add")) {
709                 if (edgePayload.getSource() == null || edgePayload.getTarget() == null) {
710                     throw new CrudException("Source/Target cannot be null for edge: " + item.getKey(),
711                             Status.BAD_REQUEST);
712                 }
713                 if (edgePayload.getSource().startsWith("$")
714                         && !vertices.contains(edgePayload.getSource().substring(1))) {
715                     throw new CrudException("Source Vertex " + edgePayload.getSource().substring(1)
716                             + " not found for Edge: " + item.getKey(), Status.BAD_REQUEST);
717                 }
718
719                 if (edgePayload.getTarget().startsWith("$")
720                         && !vertices.contains(edgePayload.getTarget().substring(1))) {
721                     throw new CrudException("Target Vertex " + edgePayload.getSource().substring(1)
722                             + " not found for Edge: " + item.getKey(), Status.BAD_REQUEST);
723                 }
724             }
725             edges.add(item.getKey());
726
727         }
728
729     }
730
731     @ApiOperation(value = "Bulk API" , notes="For example : https://<host>:9520/services/inventory/v11/bulk")
732     @ApiResponses({    
733       @ApiResponse(code = 200, message = "Success"),
734       @ApiResponse(code = 403, message = "Forbidden"), 
735       @ApiResponse(code = 400, message = "Bad Request"),
736       @ApiResponse(code = 404, message = "Not Found"),
737       @ApiResponse(code = 500, message = "Internal Server Error") })
738     @ApiImplicitParams({
739       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
740       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
741     })
742     @POST
743     @Path("/{version}/bulk/")
744     @Consumes({MediaType.APPLICATION_JSON})
745     @Produces({MediaType.APPLICATION_JSON})
746     public Response addBulk(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, 
747             @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
748             @Context HttpServletRequest req) {
749
750         LoggingUtil.initMdcContext(req, headers);
751         logger.debug("Incoming request..." + content);
752
753         ResponseBuilder responseBuilder;
754
755         try {
756             if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
757                 BulkPayload payload = BulkPayload.fromJson(content);
758                 if ((payload.getObjects() == null && payload.getRelationships() == null)
759                         || (payload.getObjects() != null && payload.getObjects().isEmpty()
760                                 && payload.getRelationships() != null && payload.getRelationships().isEmpty())) {
761                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
762                 }
763
764                 validateBulkPayload(payload);
765                 String result = graphDataService.addBulk(version, payload, headers);
766                 responseBuilder = Response.status(Status.OK).entity(result).type(mediaType);
767             } else {
768                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
769             }
770         } catch (CrudException ce) {
771             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
772         } catch (Exception e) {
773             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
774         }
775
776         setTxIdOnResponseHeader(headers, responseBuilder);
777
778         Response response = responseBuilder.build();
779         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
780         return response;
781     }
782
783     @ApiOperation(value = "Create Vertex (typeless endpoint)" , nickname="addVertex-typeless",notes = "# Payload \n"
784         + "{\r\n" +  
785         "   \"type\" :\"vertex type from oxm like comcast.nodes.sdwan.vpn\",\r\n" +       
786         "    \"properties\": {\r\n" + 
787         "        \"prop1\" : \"value\",\r\n" + 
788         "        \"prop2\" :\"value\",\r\n" +          
789         "    ..}\r\n" + 
790         " }")
791     @ApiResponses({   
792       @ApiResponse(code = 201, message = "Created"),
793       @ApiResponse(code = 403, message = "Forbidden"), 
794       @ApiResponse(code = 400, message = "Bad Request"),
795       @ApiResponse(code = 404, message = "Not Found"),
796       @ApiResponse(code = 500, message = "Internal Server Error") })
797     @ApiImplicitParams({
798       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
799       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
800     })
801     @POST
802     @Path("/{version}/")
803     @Consumes({MediaType.APPLICATION_JSON})
804     @Produces({MediaType.APPLICATION_JSON})
805     public Response addVertex(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version,
806             @PathParam("uri") @Encoded  @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
807             @Context HttpServletRequest req) {
808
809         LoggingUtil.initMdcContext(req, headers);
810         logger.debug("Incoming request..." + content);
811
812         ResponseBuilder responseBuilder;
813
814         try {
815
816             if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
817                 VertexPayload payload = VertexPayload.fromJson(content);
818                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
819                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
820                 }
821                 if (payload.getId() != null) {
822                     throw new CrudException("ID specified , use Http PUT to update Vertex", Status.BAD_REQUEST);
823                 }
824
825                 if (payload.getType() == null || payload.getType().isEmpty()) {
826                     throw new CrudException("Missing Vertex Type ", Status.BAD_REQUEST);
827                 }
828
829                 payload.setProperties(CrudServiceUtil.mergeHeaderInFoToPayload(payload.getProperties(), headers, true));
830
831                 ImmutablePair<EntityTag, String> result =
832                         graphDataService.addVertex(version, payload.getType(), payload);
833                 responseBuilder =
834                         Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType);
835             } else {
836                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
837             }
838         } catch (CrudException ce) {
839             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
840         } catch (Exception e) {
841             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
842         }
843
844         setTxIdOnResponseHeader(headers, responseBuilder);
845
846         Response response = responseBuilder.build();
847         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
848         return response;
849     }
850
851     @ApiOperation(value = "Create Edge" , notes = "# Payload \n"
852         + "{  \r\n" + 
853         "   \"source\":\"source vertex like : services/inventory/v11/vserver/0\",\r\n" + 
854         "   \"target\":\"target vertex like : services/inventory/v11/pserver/7\",\r\n" + 
855         "   \"properties\":{  \r\n" + 
856         "        \"prop1\" : \"value\",\r\n" + 
857         "        \"prop2\" :\"value\",\r\n" +  
858         "    ..}\r\n" + 
859         " }")
860     @ApiResponses({   
861       @ApiResponse(code = 201, message = "Created"),
862       @ApiResponse(code = 403, message = "Forbidden"), 
863       @ApiResponse(code = 400, message = "Bad Request"),
864       @ApiResponse(code = 404, message = "Not Found"),
865       @ApiResponse(code = 500, message = "Internal Server Error") })
866    
867     @ApiImplicitParams({
868       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
869       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),       
870     })
871     @POST
872     @Path("/relationships/{version}/{type}/")
873     @Consumes({MediaType.APPLICATION_JSON})
874     @Produces({MediaType.APPLICATION_JSON})
875     public Response addEdge(String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
876             @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers, @Context UriInfo uriInfo,
877             @Context HttpServletRequest req) {
878
879         LoggingUtil.initMdcContext(req, headers);
880         logger.debug("Incoming request..." + content);
881
882         ResponseBuilder responseBuilder;
883
884         try {
885             if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
886                 EdgePayload payload = EdgePayload.fromJson(content);
887                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
888                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
889                 }
890                 if (payload.getId() != null) {
891                     throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
892                 }
893
894                 if (payload.getType() != null && !payload.getType().equals(type)) {
895                     throw new CrudException("Edge Type mismatch", Status.BAD_REQUEST);
896                 }
897                 ImmutablePair<EntityTag, String> result = graphDataService.addEdge(version, type, payload);
898                 responseBuilder =
899                         Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType);
900             } else {
901                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
902             }
903         } catch (CrudException ce) {
904             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
905         } catch (Exception e) {
906             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
907         }
908
909         setTxIdOnResponseHeader(headers, responseBuilder);
910
911         Response response = responseBuilder.build();
912         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
913         return response;
914     }
915
916     @ApiOperation(value = "Create Edge (typeless endpoint)" , nickname="addEdge-typeless",notes = "# Payload \n"
917         + "{  \r\n" + 
918         "   \"type\":\"edge type like : tosca.relationships.HostedOn\",\r\n" +      
919         "   \"source\":\"source vertex like : services/inventory/v11/vserver/0\",\r\n" + 
920         "   \"target\":\"target vertex like : services/inventory/v11/pserver/7\",\r\n" + 
921         "   \"properties\":{  \r\n" + 
922         "        \"prop1\" : \"value\",\r\n" + 
923         "        \"prop2\" :\"value\",\r\n" +  
924         "    ..}\r\n" + 
925         " }")
926     @ApiResponses({  
927       @ApiResponse(code = 201, message = "Created"),
928       @ApiResponse(code = 403, message = "Forbidden"), 
929       @ApiResponse(code = 400, message = "Bad Request"),
930       @ApiResponse(code = 404, message = "Not Found"),
931       @ApiResponse(code = 500, message = "Internal Server Error") })
932     @ApiImplicitParams({
933       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
934       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
935     })
936     @POST
937     @Path("/relationships/{version}/")
938     @Consumes({MediaType.APPLICATION_JSON})
939     @Produces({MediaType.APPLICATION_JSON})
940     public Response addEdge(String content, @PathParam("version")  @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri,
941             @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) {
942
943         LoggingUtil.initMdcContext(req, headers);
944         logger.debug("Incoming request..." + content);
945
946         ResponseBuilder responseBuilder;
947
948         try {
949             if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
950                 EdgePayload payload = EdgePayload.fromJson(content);
951                 if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
952                     throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
953                 }
954                 if (payload.getId() != null) {
955                     throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST);
956                 }
957
958                 if (payload.getType() == null || payload.getType().isEmpty()) {
959                     payload.setType(CrudServiceUtil.determineEdgeType(payload, version));
960                 }
961
962                 ImmutablePair<EntityTag, String> result = graphDataService.addEdge(version, payload.getType(), payload);
963                 responseBuilder =
964                         Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType);
965             } else {
966                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
967             }
968         } catch (CrudException ce) {
969             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
970         } catch (Exception e) {
971             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
972         }
973
974         setTxIdOnResponseHeader(headers, responseBuilder);
975
976         Response response = responseBuilder.build();
977         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
978         return response;
979     }
980
981     @ApiOperation(value = "Delete Vertex" , notes="For example : https://<host>:9520/services/inventory/v11/pserver/<id>")
982     @ApiResponses({  
983       @ApiResponse(code = 200, message = "Success"),
984       @ApiResponse(code = 403, message = "Forbidden"), 
985       @ApiResponse(code = 400, message = "Bad Request"),
986       @ApiResponse(code = 404, message = "Not Found"),
987       @ApiResponse(code = 500, message = "Internal Server Error") })
988     @ApiImplicitParams({
989       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
990       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
991     })
992     @DELETE
993     @Path("/{version}/{type}/{id}")
994     @Consumes({MediaType.APPLICATION_JSON})
995     @Produces({MediaType.APPLICATION_JSON})
996     public Response deleteVertex(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
997             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true)  String uri, @Context HttpHeaders headers,
998             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
999
1000         LoggingUtil.initMdcContext(req, headers);
1001         logger.debug("Incoming request..." + content);
1002
1003         ResponseBuilder responseBuilder;
1004
1005         try {
1006             if (validateRequest(req, uri, content, Action.DELETE, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
1007                 String result = graphDataService.deleteVertex(version, id, type);
1008                 responseBuilder = Response.status(Status.OK).entity(result).type(mediaType);
1009             } else {
1010                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
1011             }
1012         } catch (CrudException ce) {
1013             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
1014         } catch (Exception e) {
1015             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
1016         }
1017
1018         setTxIdOnResponseHeader(headers, responseBuilder);
1019
1020         Response response = responseBuilder.build();
1021         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
1022         return response;
1023     }
1024
1025     @ApiOperation(value = "Delete Edge" , notes="For example : https://<host>:9520/services/inventory/v11/pserver/<id>")
1026     @ApiResponses({ 
1027       @ApiResponse(code = 200, message = "Success"),
1028       @ApiResponse(code = 403, message = "Forbidden"), 
1029       @ApiResponse(code = 400, message = "Bad Request"),
1030       @ApiResponse(code = 404, message = "Not Found"),
1031       @ApiResponse(code = 500, message = "Internal Server Error") })
1032     @ApiImplicitParams({
1033       @ApiImplicitParam(name = "X-FromAppId", required = true, dataType = "string", paramType = "header"),
1034       @ApiImplicitParam(name = "X-TransactionId",  required = true, dataType = "string", paramType = "header"),    
1035     })
1036     @DELETE
1037     @Path("/relationships/{version}/{type}/{id}")
1038     @Consumes({MediaType.APPLICATION_JSON})
1039     @Produces({MediaType.APPLICATION_JSON})
1040     public Response deleteEdge(@ApiParam(hidden=true) String content, @PathParam("version") @ApiParam(value="oxm model version",defaultValue="v13") String version, @PathParam("type") String type,
1041             @PathParam("id") String id, @PathParam("uri") @Encoded @ApiParam(hidden=true) String uri, @Context HttpHeaders headers,
1042             @Context UriInfo uriInfo, @Context HttpServletRequest req) {
1043
1044         LoggingUtil.initMdcContext(req, headers);
1045         logger.debug("Incoming request..." + content);
1046
1047         ResponseBuilder responseBuilder;
1048
1049         try {
1050             if (validateRequest(req, uri, content, Action.DELETE, CrudServiceConstants.CRD_AUTH_POLICY_NAME, headers)) {
1051                 String result = graphDataService.deleteEdge(version, id, type);
1052                 responseBuilder = Response.status(Status.OK).entity(result).type(mediaType);
1053             } else {
1054                 responseBuilder = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON);
1055             }
1056         } catch (CrudException ce) {
1057             responseBuilder = Response.status(ce.getHttpStatus()).entity(ce.getMessage());
1058         } catch (Exception e) {
1059             responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage());
1060         }
1061
1062         setTxIdOnResponseHeader(headers, responseBuilder);
1063
1064         Response response = responseBuilder.build();
1065         LoggingUtil.logRestRequest(logger, auditLogger, req, response);
1066         return response;
1067     }
1068
1069     protected boolean validateRequest(HttpServletRequest req, String uri, String content, Action action,
1070             String authPolicyFunctionName, HttpHeaders headers) throws CrudException {
1071         
1072         if (!authorizationEnabled) {
1073             validateRequestHeader(headers);
1074             return true;
1075         }
1076         
1077         boolean isValid = false;
1078         try {
1079             String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite");
1080             String authUser = null;
1081             if (cipherSuite != null) {
1082                 X509Certificate[] certChain =
1083                         (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
1084                 X509Certificate clientCert = certChain[0];
1085                 X500Principal subjectDn = clientCert.getSubjectX500Principal();
1086                 authUser = subjectDn.toString();
1087             }
1088             if (null != authUser) {
1089                 isValid = this.auth.validateRequest(authUser.toLowerCase(),
1090                         action.toString() + ":" + authPolicyFunctionName);
1091             }
1092         } catch (Exception e) {
1093             logResult(action, uri, e);
1094             return false;
1095         }
1096
1097         validateRequestHeader(headers);
1098
1099         return isValid;
1100     }
1101
1102     public void validateRequestHeader(HttpHeaders headers) throws CrudException {
1103         String sourceOfTruth = null;
1104         if (headers.getRequestHeaders().containsKey("X-FromAppId")) {
1105             sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
1106         }
1107
1108         if (sourceOfTruth == null || sourceOfTruth.trim() == "") {
1109             throw new CrudException("Invalid request, Missing X-FromAppId header", Status.BAD_REQUEST);
1110         }
1111
1112         String transId = null;
1113         if (headers.getRequestHeaders().containsKey("X-TransactionId")) {
1114             transId = headers.getRequestHeaders().getFirst("X-TransactionId");
1115         }
1116
1117         if (transId == null || transId.trim() == "") {
1118             throw new CrudException("Invalid request, Missing X-TransactionId header", Status.BAD_REQUEST);
1119         }
1120     }
1121
1122     void logResult(Action op, String uri, Exception e) {
1123
1124         logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL, op.toString(), uri,
1125                 Arrays.toString(e.getStackTrace()));
1126
1127         // Clear the MDC context so that no other transaction inadvertently
1128         // uses our transaction id.
1129         MDC.clear();
1130     }
1131
1132     private Map<String, String> addParams(UriInfo info, boolean filter, String type, String version) {
1133         String propertiesKey = CrudProperties.get(CrudServiceConstants.CRD_COLLECTION_PROPERTIES_KEY);
1134         Map<String, String> params = new HashMap<String, String>();
1135         params.put(CrudServiceConstants.CRD_RESERVED_VERSION, version);
1136         params.put(CrudServiceConstants.CRD_RESERVED_NODE_TYPE, type);
1137         if (filter) {
1138             for (Map.Entry<String, List<String>> e : info.getQueryParameters().entrySet()) {
1139                 if (!e.getKey().equals(propertiesKey)) {
1140                     params.put(e.getKey(), e.getValue().get(0));
1141                 }
1142             }
1143         } else {
1144             for (Map.Entry<String, List<String>> e : info.getQueryParameters().entrySet()) {
1145                 params.put(e.getKey(), e.getValue().get(0));
1146             }
1147         }
1148         return params;
1149     }
1150
1151     private void setTxIdOnResponseHeader(HttpHeaders headers, ResponseBuilder responseBuilder) {
1152         String txId = headers.getHeaderString(TRANSACTIONID_HEADER);
1153         if (txId != null) {
1154             responseBuilder.header(TRANSACTIONID_HEADER, txId);
1155         }
1156     }
1157 }