/** * ============LICENSE_START======================================================= * Gizmo * ================================================================================ * Copyright © 2017 AT&T Intellectual Property. * Copyright © 2017 Amdocs * All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= * * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ package org.onap.crud.service; import java.security.cert.X509Certificate; import java.util.AbstractMap; 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; import javax.ws.rs.Encoded; import javax.ws.rs.POST; import javax.ws.rs.PUT; 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.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 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; import org.onap.crud.service.CrudRestService.Action; import org.onap.crud.util.CrudServiceConstants; import org.onap.schema.RelationshipSchemaLoader; import org.onap.schema.RelationshipSchemaValidator; import org.slf4j.MDC; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; /** * This defines a set of REST endpoints which allow clients to create or update graph edges * where the edge rules defined by the A&AI will be invoked to automatically populate the * defined edge properties. */ 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, @PathParam("uri") @Encoded String uri, @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); // Do some basic validation on the payload. if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); } if (payload.getId() != null) { throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST); } 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 " + RelationshipSchemaLoader.getLatestSchemaVersion() ); } // Now, create our edge in the graph store. String result = graphDataService.addEdge(RelationshipSchemaLoader.getLatestSchemaVersion(), type, payload); response = Response.status(Status.CREATED).entity(result).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, @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { LoggingUtil.initMdcContext(req, headers); 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); // Do some basic validation on the payload. if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); } if (payload.getId() != null) { throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST); } 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(RelationshipSchemaLoader.getLatestSchemaVersion(), payload.getType(), payload); response = Response.status(Status.CREATED).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; } /** * Upserts a relationship into the graph, automatically populating the edge properties * based on the A&AI edge rules. The behaviour is as follows: *
*
* 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