summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/crud/service/AaiResourceService.java
diff options
context:
space:
mode:
authorSotiropoulos, Ioannis (is948x) <Ioannis.Sotiropoulos@amdocs.com>2018-06-15 15:32:01 +0100
committerMichael Arrastia <MArrasti@amdocs.com>2018-06-18 11:33:18 +0100
commitb348af8ed2c4192f88169b37bf53fa25b8a7a681 (patch)
tree3ce66feb7909f645536a8d0eb5ad2a7879d3ab6c /src/main/java/org/onap/crud/service/AaiResourceService.java
parent00832f054dd0c21492af531548e321ea25cdb8b4 (diff)
ETags on resources
An etag should be generated (by Champ) when creating a resource (edge or vertex). The Champ microservice should return this etag in the response header. Gizmo should also return the etag in it's response header (Gizmo will receive the etag from Champ). Issue-ID: AAI-1196 Change-Id: Ie16f871eccbceeccde037e73e0de0d96eeba18bd Signed-off-by: Sotiropoulos, Ioannis (is948x) <Ioannis.Sotiropoulos@amdocs.com>
Diffstat (limited to 'src/main/java/org/onap/crud/service/AaiResourceService.java')
-rw-r--r--src/main/java/org/onap/crud/service/AaiResourceService.java249
1 files changed, 123 insertions, 126 deletions
diff --git a/src/main/java/org/onap/crud/service/AaiResourceService.java b/src/main/java/org/onap/crud/service/AaiResourceService.java
index c9a5805..afabe7e 100644
--- a/src/main/java/org/onap/crud/service/AaiResourceService.java
+++ b/src/main/java/org/onap/crud/service/AaiResourceService.java
@@ -26,7 +26,6 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-
import javax.security.auth.x500.X500Principal;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
@@ -37,20 +36,21 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
+import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response.Status;
-
+import javax.ws.rs.core.UriInfo;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
import org.onap.aai.exceptions.AAIException;
import org.onap.aai.serialization.db.EdgeProperty;
import org.onap.aai.serialization.db.EdgeRule;
import org.onap.aai.serialization.db.EdgeRules;
import org.onap.aai.serialization.db.EdgeType;
import org.onap.aaiauth.auth.Auth;
-import org.onap.aai.cl.api.Logger;
-import org.onap.aai.cl.eelf.LoggerFactory;
import org.onap.crud.exception.CrudException;
import org.onap.crud.logging.CrudServiceMsgs;
import org.onap.crud.logging.LoggingUtil;
@@ -59,7 +59,6 @@ import org.onap.crud.util.CrudServiceConstants;
import org.onap.schema.EdgeRulesLoader;
import org.onap.schema.RelationshipSchemaValidator;
import org.slf4j.MDC;
-
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
@@ -74,78 +73,78 @@ public class AaiResourceService {
private String mediaType = MediaType.APPLICATION_JSON;
public static final String HTTP_PATCH_METHOD_OVERRIDE = "X-HTTP-Method-Override";
-
+
private Auth auth;
AbstractGraphDataService graphDataService;
Gson gson = new Gson();
-
+
private Logger logger = LoggerFactory.getInstance().getLogger(AaiResourceService.class.getName());
private Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(AaiResourceService.class.getName());
-
+
public AaiResourceService() {}
-
+
/**
* Creates a new instance of the AaiResourceService.
- *
+ *
* @param crudGraphDataService - Service used for interacting with the graph.
- *
+ *
* @throws Exception
*/
public AaiResourceService(AbstractGraphDataService graphDataService) throws Exception {
this.graphDataService = graphDataService;
this.auth = new Auth(CrudServiceConstants.CRD_AUTH_FILE);
}
-
+
/**
* Perform any one-time initialization required when starting the service.
*/
public void startup() {
-
+
if(logger.isDebugEnabled()) {
logger.debug("AaiResourceService started!");
}
}
-
-
+
+
/**
* Creates a new relationship in the graph, automatically populating the edge
* properties based on the A&AI edge rules.
- *
+ *
* @param content - Json structure describing the relationship to create.
* @param type - Relationship type supplied as a URI parameter.
* @param uri - Http request uri
* @param headers - Http request headers
* @param uriInfo - Http URI info field
* @param req - Http request structure.
- *
+ *
* @return - Standard HTTP response.
*/
@POST
@Path("/relationships/{type}/")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
- public Response createRelationship(String content,
- @PathParam("type") String type,
+ public Response createRelationship(String content,
+ @PathParam("type") String type,
@PathParam("uri") @Encoded String uri,
- @Context HttpHeaders headers,
+ @Context HttpHeaders headers,
@Context UriInfo uriInfo,
@Context HttpServletRequest req) {
-
+
LoggingUtil.initMdcContext(req, headers);
if(logger.isDebugEnabled()) {
logger.debug("Incoming request..." + content);
}
-
+
Response response = null;
if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
-
+
try {
-
+
// Extract the edge payload from the request.
- EdgePayload payload = EdgePayload.fromJson(content);
-
+ EdgePayload payload = EdgePayload.fromJson(content);
+
// Do some basic validation on the payload.
if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
@@ -156,50 +155,50 @@ public class AaiResourceService {
if (payload.getType() != null && !payload.getType().equals(type)) {
throw new CrudException("Edge Type mismatch", Status.BAD_REQUEST);
}
-
+
// Apply the edge rules to our edge.
payload = applyEdgeRulesToPayload(payload);
-
+
if(logger.isDebugEnabled()) {
logger.debug("Creating AAI edge using version " + EdgeRulesLoader.getLatestSchemaVersion() );
}
-
+
// Now, create our edge in the graph store.
- String result = graphDataService.addEdge(EdgeRulesLoader.getLatestSchemaVersion(), type, payload);
- response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
-
+ ImmutablePair<EntityTag, String> result = graphDataService.addEdge(EdgeRulesLoader.getLatestSchemaVersion(), type, payload);
+ response = Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType).build();
+
} catch (CrudException e) {
response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
- }
+ }
}
-
+
LoggingUtil.logRestRequest(logger, auditLogger, req, response);
return response;
}
-
-
+
+
/**
* Creates a new relationship in the graph, automatically populating the edge
* properties based on the A&AI edge rules.
- *
+ *
* @param content - Json structure describing the relationship to create.
* @param uri - Http request uri
* @param headers - Http request headers
* @param uriInfo - Http URI info field
* @param req - Http request structure.
- *
+ *
* @return - Standard HTTP response.
- *
+ *
*/
@POST
@Path("/relationships/")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
- public Response createRelationship(String content,
- @PathParam("uri") @Encoded String uri,
+ public Response createRelationship(String content,
+ @PathParam("uri") @Encoded String uri,
@Context HttpHeaders headers,
- @Context UriInfo uriInfo,
+ @Context UriInfo uriInfo,
@Context HttpServletRequest req) {
LoggingUtil.initMdcContext(req, headers);
@@ -210,10 +209,10 @@ public class AaiResourceService {
if (validateRequest(req, uri, content, Action.POST, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
try {
-
+
// Extract the edge payload from the request.
EdgePayload payload = EdgePayload.fromJson(content);
-
+
// Do some basic validation on the payload.
if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
@@ -224,14 +223,14 @@ public class AaiResourceService {
if (payload.getType() == null || payload.getType().isEmpty()) {
throw new CrudException("Missing Edge Type ", Status.BAD_REQUEST);
}
-
+
// Apply the edge rules to our edge.
payload = applyEdgeRulesToPayload(payload);
-
+
// Now, create our edge in the graph store.
- String result = graphDataService.addEdge(EdgeRulesLoader.getLatestSchemaVersion(), payload.getType(), payload);
- response = Response.status(Status.CREATED).entity(result).type(mediaType).build();
-
+ ImmutablePair<EntityTag, String> result = graphDataService.addEdge(EdgeRulesLoader.getLatestSchemaVersion(), payload.getType(), payload);
+ response = Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType).build();
+
} catch (CrudException ce) {
response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
} catch (Exception e) {
@@ -246,17 +245,17 @@ public class AaiResourceService {
return response;
}
-
-
+
+
/**
* Upserts a relationship into the graph, automatically populating the edge properties
* based on the A&AI edge rules. The behaviour is as follows:
* <p>
- * <li>If no relationship with the supplied identifier already exists, then a new relationship
+ * <li>If no relationship with the supplied identifier already exists, then a new relationship
* is created with that id.<br>
- * <li>If a relationship with the supplied id DOES exist, then it is replaced with the supplied
+ * <li>If a relationship with the supplied id DOES exist, then it is replaced with the supplied
* content.
- *
+ *
* @param content - Json structure describing the relationship to create.
* @param type - Relationship type supplied as a URI parameter.
* @param id - Edge identifier.
@@ -264,19 +263,19 @@ public class AaiResourceService {
* @param headers - Http request headers
* @param uriInfo - Http URI info field
* @param req - Http request structure.
- *
+ *
* @return - Standard HTTP response.
*/
@PUT
@Path("/relationships/{type}/{id}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
- public Response upsertEdge(String content,
- @PathParam("type") String type,
+ public Response upsertEdge(String content,
+ @PathParam("type") String type,
@PathParam("id") String id,
- @PathParam("uri") @Encoded String uri,
+ @PathParam("uri") @Encoded String uri,
@Context HttpHeaders headers,
- @Context UriInfo uriInfo,
+ @Context UriInfo uriInfo,
@Context HttpServletRequest req) {
LoggingUtil.initMdcContext(req, headers);
@@ -284,12 +283,12 @@ public class AaiResourceService {
Response response = null;
if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) {
-
+
try {
-
+
// Extract the edge payload from the request.
EdgePayload payload = EdgePayload.fromJson(content);
-
+
// Do some basic validation on the payload.
if (payload.getProperties() == null || payload.getProperties().isJsonNull()) {
throw new CrudException("Invalid request Payload", Status.BAD_REQUEST);
@@ -297,47 +296,45 @@ public class AaiResourceService {
if (payload.getId() != null && !payload.getId().equals(id)) {
throw new CrudException("ID Mismatch", Status.BAD_REQUEST);
}
-
+
// Apply the edge rules to our edge.
payload = applyEdgeRulesToPayload(payload);
-
- String result;
+ ImmutablePair<EntityTag, String> result;
if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null &&
headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE).equalsIgnoreCase("PATCH")) {
result = graphDataService.patchEdge(EdgeRulesLoader.getLatestSchemaVersion(), id, type, payload);
+ response = Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey()).build();
} else {
-
result = graphDataService.updateEdge(EdgeRulesLoader.getLatestSchemaVersion(), id, type, payload);
+ response = Response.status(Status.OK).entity(result.getValue()).type(mediaType).tag(result.getKey()).build();
}
- response = Response.status(Status.OK).entity(result).type(mediaType).build();
-
} catch (CrudException ce) {
response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();
} catch (Exception e) {
response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
-
+
} else {
-
+
response = Response.status(Status.FORBIDDEN).entity(content)
.type(MediaType.APPLICATION_JSON).build();
}
-
+
LoggingUtil.logRestRequest(logger, auditLogger, req, response);
return response;
}
-
-
+
+
/**
- * Retrieves the properties defined in the edge rules for a relationship between the
+ * Retrieves the properties defined in the edge rules for a relationship between the
* supplied vertex types.
- *
+ *
* @param sourceVertexType - Type of source vertex for the relationship.
* @param targetVertexType - Type of target vertex for the relationship.
- *
+ *
* @return - The defined properties for the relationship type.
- *
+ *
* @throws CrudException
*/
private Map<EdgeProperty, String> getEdgeRuleProperties(String sourceVertexType, String targetVertexType) throws CrudException {
@@ -345,119 +342,119 @@ public class AaiResourceService {
if(logger.isDebugEnabled()) {
logger.debug("Lookup db edge rules for " + sourceVertexType + " -> " + targetVertexType);
}
-
+
EdgeRules rules = EdgeRules.getInstance();
EdgeRule rule;
try {
-
+
if(logger.isDebugEnabled()) {
logger.debug("Lookup by edge type TREE");
}
-
+
// We have no way of knowing in advance whether our relationship is considered to
// be a tree or cousing relationship, so try looking it up as a tree type first.
rule = rules.getEdgeRule(EdgeType.TREE, sourceVertexType, targetVertexType);
-
+
} catch (AAIException e) {
try {
-
+
if(logger.isDebugEnabled()) {
logger.debug("Lookup by edge type COUSIN");
}
-
+
// If we are here, then our lookup by 'tree' type failed, so try looking it up
// as a 'cousin' relationship.
rule = rules.getEdgeRule(EdgeType.COUSIN, sourceVertexType, targetVertexType);
-
+
} catch (AAIException e1) {
-
+
// If we're here then we failed to find edge rules for this relationship. Time to
// give up...
throw new CrudException("No edge rules for " + sourceVertexType + " -> " + targetVertexType, Status.NOT_FOUND);
}
} catch (Exception e) {
-
- throw new CrudException("General failure getting edge rule properties - " +
+
+ throw new CrudException("General failure getting edge rule properties - " +
e.getMessage(), Status.INTERNAL_SERVER_ERROR);
}
-
+
return rule.getEdgeProperties();
}
-
-
+
+
/**
* This method takes an inbound edge request payload, looks up the edge rules for the
* sort of relationship defined in the payload, and automatically applies the defined
* edge properties to it.
- *
+ *
* @param payload - The original edge request payload
- *
+ *
* @return - An updated edge request payload, with the properties defined in the edge
* rules automatically populated.
- *
+ *
* @throws CrudException
*/
public EdgePayload applyEdgeRulesToPayload(EdgePayload payload) throws CrudException {
-
+
// Extract the types for both the source and target vertices.
String srcType = RelationshipSchemaValidator.vertexTypeFromUri(payload.getSource());
String tgtType = RelationshipSchemaValidator.vertexTypeFromUri(payload.getTarget());
// Now, get the default properties for this edge based on the edge rules definition...
Map<EdgeProperty, String> props = getEdgeRuleProperties(srcType, tgtType);
-
+
// ...and merge them with any custom properties provided in the request.
JsonElement mergedProperties = mergeProperties(payload.getProperties(), props);
payload.setProperties(mergedProperties);
-
-
+
+
if(logger.isDebugEnabled()) {
logger.debug("Edge properties after applying rules for '" + srcType + " -> " + tgtType + "': " + mergedProperties);
}
-
+
return payload;
}
-
-
+
+
/**
* Given a set of edge properties extracted from an edge request payload and a set of properties
* taken from the db edge rules, this method merges them into one set of properties.
* <p>
* If the client has attempted to override the defined value for a property in the db edge rules
* then the request will be rejected as invalid.
- *
+ *
* @param propertiesFromRequest - Set of properties from the edge request.
* @param propertyDefaults - Set of properties from the db edge rules.
- *
+ *
* @return - A merged set of properties.
- *
+ *
* @throws CrudException
*/
public JsonElement mergeProperties(JsonElement propertiesFromRequest, Map<EdgeProperty, String> propertyDefaults) throws CrudException {
-
+
// Convert the properties from the edge payload into something we can
// manipulate.
Set<Map.Entry<String, JsonElement>> properties = new HashSet<Map.Entry<String, JsonElement>>();
properties.addAll(propertiesFromRequest.getAsJsonObject().entrySet());
-
+
Set<String> propertyKeys = new HashSet<String>();
for(Map.Entry<String, JsonElement> property : properties) {
propertyKeys.add(property.getKey());
}
-
+
// Now, merge in the properties specified in the Db Edge Rules.
for(EdgeProperty defProperty : propertyDefaults.keySet()) {
-
+
// If the edge rules property was explicitly specified by the
// client then we will reject the request...
if(!propertyKeys.contains(defProperty.toString())) {
properties.add(new AbstractMap.SimpleEntry<String, JsonElement>(defProperty.toString(),
- (JsonElement)(new JsonPrimitive(propertyDefaults.get(defProperty)))));
-
+ (new JsonPrimitive(propertyDefaults.get(defProperty)))));
+
} else {
- throw new CrudException("Property " + defProperty + " defined in db edge rules can not be overriden by the client.",
+ throw new CrudException("Property " + defProperty + " defined in db edge rules can not be overriden by the client.",
Status.BAD_REQUEST);
- }
+ }
}
Object[] propArray = properties.toArray();
@@ -465,7 +462,7 @@ public class AaiResourceService {
sb.append("{");
boolean first=true;
for(int i=0; i<propArray.length; i++) {
-
+
Map.Entry<String, JsonElement> entry = (Entry<String, JsonElement>) propArray[i];
if(!first) {
sb.append(",");
@@ -474,7 +471,7 @@ public class AaiResourceService {
first=false;
}
sb.append("}");
-
+
// We're done. Return the result as a JsonElement.
return gson.fromJson(sb.toString(), JsonElement.class);
}
@@ -482,45 +479,45 @@ public class AaiResourceService {
/**
* Invokes authentication validation on an incoming HTTP request.
- *
+ *
* @param req - The HTTP request.
* @param uri - HTTP URI
* @param content - Payload of the HTTP request.
* @param action - What HTTP action is being performed (GET/PUT/POST/PATCH/DELETE)
* @param authPolicyFunctionName - Policy function being invoked.
- *
+ *
* @return true - if the request passes validation,
* false - otherwise.
*/
- protected boolean validateRequest(HttpServletRequest req,
- String uri,
+ protected boolean validateRequest(HttpServletRequest req,
+ String uri,
String content,
- Action action,
+ Action action,
String authPolicyFunctionName) {
try {
String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite");
String authUser = null;
if (cipherSuite != null) {
-
+
X509Certificate[] certChain = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
X509Certificate clientCert = certChain[0];
X500Principal subjectDn = clientCert.getSubjectX500Principal();
authUser = subjectDn.toString();
}
-
+
return this.auth.validateRequest(authUser.toLowerCase(), action.toString() + ":" + authPolicyFunctionName);
-
+
} catch (Exception e) {
logResult(action, uri, e);
return false;
}
}
-
+
protected void logResult(Action op, String uri, Exception e) {
- logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL,
- op.toString(),
- uri,
+ logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL,
+ op.toString(),
+ uri,
e.getStackTrace().toString());
// Clear the MDC context so that no other transaction inadvertently