diff options
author | 2018-03-05 16:33:32 +0000 | |
---|---|---|
committer | 2018-03-07 11:17:22 +0000 | |
commit | c74f7b13b573386e70c10721fc391624ee792ed6 (patch) | |
tree | b44995474ff938b4b03c9b234f95b71bc75d6b79 /champ-service/src/main/java | |
parent | 9fc28cff11a4b570618c0f533ce9de6209a5dd0c (diff) |
Port champ-microservice project restructure
Includes project restructure and introduction of a parent pom. The
original source folder and core functionality is now held within champ-lib, with champ-service
forming the ajsc microservice from which it injects champ-lib core
functionality.
Issue-ID: AAI-813
Change-Id: I2ce0c4a70e485665276e7955572de23969deb706
Signed-off-by: michaere <michaere@amdocs.com>
Diffstat (limited to 'champ-service/src/main/java')
20 files changed, 2956 insertions, 0 deletions
diff --git a/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java b/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java new file mode 100644 index 0000000..3d7e074 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java @@ -0,0 +1,568 @@ +package org.onap.champ; + +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Timer; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +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.QueryParam; +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.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException; +import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException; +import org.onap.aai.champcore.exceptions.ChampTransactionException; +import org.onap.aai.champcore.exceptions.ChampUnmarshallingException; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.async.ChampAsyncRequestProcessor; +import org.onap.champ.entity.ChampObjectDeserializer; +import org.onap.champ.entity.ChampObjectSerializer; +import org.onap.champ.entity.ChampRelationshipDeserializer; +import org.onap.champ.entity.ChampRelationshipSerializer; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.service.ChampDataService; +import org.onap.champ.service.logging.ChampMsgs; +import org.onap.champ.service.logging.LoggingUtil; +import org.onap.champ.util.ChampProperties; +import org.onap.champ.util.ChampServiceConstants; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +@Path(value = "/") +public class ChampRESTAPI { + + private ObjectMapper mapper; + + private ChampDataService champDataService; + private String TRANSACTION_METHOD = "method"; + private Timer timer; + + private Logger logger = LoggerFactory.getInstance().getLogger(ChampRESTAPI.class); + Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(ChampRESTAPI.class.getName()); + private static Logger metricsLogger = LoggerFactory.getInstance().getMetricsLogger(ChampRESTAPI.class.getName()); + + public ChampRESTAPI(ChampDataService champDataService, ChampAsyncRequestProcessor champAsyncRequestProcessor) { + this.champDataService = champDataService; + + // Async request handling is optional. + if (champAsyncRequestProcessor != null) { + timer = new Timer("ChampAsyncRequestProcessor-1"); + timer.schedule(champAsyncRequestProcessor, champAsyncRequestProcessor.getRequestPollingTimeSeconds(), + champAsyncRequestProcessor.getRequestPollingTimeSeconds()); + } + + mapper = new ObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addSerializer(ChampObject.class, new ChampObjectSerializer()); + module.addDeserializer(ChampObject.class, new ChampObjectDeserializer()); + module.addSerializer(ChampRelationship.class, new ChampRelationshipSerializer()); + module.addDeserializer(ChampRelationship.class, new ChampRelationshipDeserializer()); + mapper.registerModule(module); + } + + @GET + @Path("echo") + @Produces(MediaType.TEXT_PLAIN) + public Response echo() { + return Response.ok().entity("alive").build(); + } + + @GET + @Path("objects/{objectId}") + @Produces(MediaType.APPLICATION_JSON) + public Response getObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId); + + Response response = null; + ChampObject retrieved; + + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + retrieved = champDataService.getObject(objectId, Optional.ofNullable(transaction)); + if (retrieved == null) { + response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build(); + } else { + response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).build(); + } + + } catch (JsonProcessingException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } finally { + logger.debug(response.getEntity().toString()); + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + + return response; + } + + @DELETE + @Path("objects/{objectId}") + public Response deleteObject(@PathParam("objectId") String objectId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId); + ChampObject retrieved; + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + champDataService.deleteObject(objectId, Optional.ofNullable(transaction)); + + response = Response.status(Status.OK).build(); + } catch (ChampObjectNotExistsException e) { + response = Response.status(Status.NOT_FOUND).entity(objectId + " not found").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (ChampTransactionException | ChampUnmarshallingException e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @POST + @Path("objects") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response postObject(String champObj, @QueryParam("transactionId") String tId, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, champObj); + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + ChampObject champObject = mapper.readValue(champObj, ChampObject.class); + + ChampObject created = champDataService.storeObject(champObject, Optional.ofNullable(transaction)); + response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @PUT + @Path("objects/{objectId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response putObject(@PathParam("objectId") String objectId, String champObj, + @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId + " " + champObj); + + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + + ChampObject co = mapper.readValue(champObj, ChampObject.class); + // check if key is present or if it equals the key that is in the URI + ChampObject updated = champDataService.replaceObject(co, objectId, Optional.ofNullable(transaction)); + + response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("objects/relationships/{oId}") + @Produces(MediaType.APPLICATION_JSON) + public Response getEdges(@PathParam("oId") String oId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + List<ChampRelationship> retrieved; + Optional<ChampObject> rObject; + Response response = null; + ChampTransaction transaction = null; + try { + + retrieved = champDataService.getRelationshipsByObject(oId, Optional.ofNullable(transaction)); + response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).build(); + } catch (JsonProcessingException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("objects/filter/") + @Produces(MediaType.APPLICATION_JSON) + public Response filterObject(@Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + String propertiesKey = ChampProperties.get(ChampServiceConstants.CHAMP_COLLECTION_PROPERTIES_KEY); + List<ChampObject> objects; + Map<String, Object> filter = new HashMap<>(); + + for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) { + if (!e.getKey().equals(propertiesKey)) { + filter.put(e.getKey(), e.getValue().get(0)); + } + } + + HashSet<String> properties; + if (uriInfo.getQueryParameters().containsKey(propertiesKey)) { + properties = new HashSet<>(uriInfo.getQueryParameters().get(propertiesKey)); + } else { + properties = new HashSet<>(); + } + + Response response = null; + try { + objects = champDataService.queryObjects(filter, properties); + response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(mapper.writeValueAsString(objects)) + .build(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException e1) { + response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("relationships/{rId}") + @Produces(MediaType.APPLICATION_JSON) + public Response getRelationship(@PathParam("rId") String rId, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, rId); + ChampRelationship retrieved; + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + retrieved = champDataService.getRelationship(rId, Optional.ofNullable(transaction)); + if (retrieved == null) { + response = Response.status(Status.NOT_FOUND).entity(rId + " not found").build(); + return response; + } + response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).build(); + + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @POST + @Path("relationships") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response postRelationships(String relationship, @QueryParam("transactionId") String tId, + @Context HttpHeaders headers, @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship); + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class); + + ChampRelationship created = champDataService.storeRelationship(r, Optional.ofNullable(transaction)); + + response = Response.status(Status.CREATED).entity(mapper.writeValueAsString(created)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @PUT + @Path("relationships/{rId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateRelationship(@PathParam("rId") String rId, String relationship, + @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship); + + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + ChampRelationship r = mapper.readValue(relationship, ChampRelationship.class); + ChampRelationship updated = champDataService.updateRelationship(r, rId, Optional.ofNullable(transaction)); + + response = Response.status(Status.OK).entity(mapper.writeValueAsString(updated)).build(); + } catch (IOException e) { + response = Response.status(Status.BAD_REQUEST).entity("Unable to parse the payload").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @DELETE + @Path("relationships/{relationshipId}") + public Response deleteRelationship(@PathParam("relationshipId") String relationshipId, + @QueryParam("transactionId") String tId, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationshipId); + + Response response = null; + try { + ChampTransaction transaction = champDataService.getTransaction(tId); + if (tId != null && transaction == null) { + throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST); + } + champDataService.deleteRelationship(relationshipId, Optional.ofNullable(transaction)); + response = Response.status(Status.OK).build(); + + } catch (ChampRelationshipNotExistsException e) { + response = Response.status(Status.NOT_FOUND).entity(relationshipId + " not found").build(); + } catch (ChampServiceException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (ChampTransactionException | ChampUnmarshallingException e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "DELETE", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @GET + @Path("relationships/filter/") + @Produces(MediaType.APPLICATION_JSON) + public Response filterMethod(@Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + List<ChampRelationship> list; + Map<String, Object> filter = new HashMap<>(); + for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) { + filter.put(e.getKey(), e.getValue().get(0)); + } + Response response = null; + try { + list = champDataService.queryRelationships(filter); + response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(mapper.writeValueAsString(list)) + .build(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException e1) { + response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @POST + @Path("transaction") + @Produces(MediaType.TEXT_PLAIN) + public Response openTransaction(@Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + Status s; + String transaction = champDataService.openTransaction(); + + s = Status.OK; + Response response = Response.status(s).entity(transaction).build(); + logger.info(ChampMsgs.PROCESS_EVENT, "Opened Transaction with ID: " + transaction, s.toString()); + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", Long.toString(System.currentTimeMillis() - startTimeInMs)); + return response; + } + + @GET + @Path("transaction/{tId}") + public Response getSpecificTransaction(@PathParam("tId") String tId, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + + Response response = null; + ChampTransaction transaction = champDataService.getTransaction(tId); + if (transaction == null) { + response = Response.status(Status.NOT_FOUND).entity("transaction " + tId + " not found").build(); + return response; + } + + try { + response = Response.status(Status.OK).entity(mapper.writeValueAsString(tId + " is OPEN")).build(); + } catch (JsonProcessingException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "GET", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + + @PUT + @Path("transaction/{tId}") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_JSON) + public Response updateTransaction(String t, @PathParam("tId") String tId, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + long startTimeInMs = System.currentTimeMillis(); + logger.info(ChampMsgs.INCOMING_REQUEST, tId, "COMMIT/ROLLBACK"); + + Response response = null; + try { + JSONObject jsonObj = new JSONObject(t); + String method = jsonObj.getString(this.TRANSACTION_METHOD); + + if (method.equals("commit")) { + champDataService.commitTransaction(tId); + response = Response.status(Status.OK).entity("COMMITTED").build(); + + } else if (method.equals("rollback")) { + champDataService.rollbackTransaction(tId); + response = Response.status(Status.OK).entity("ROLLED BACK").build(); + } else { + response = Response.status(Status.BAD_REQUEST).entity("Invalid Method: " + method).build(); + return response; + } + + } catch (ChampTransactionException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (JSONException e) { + response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } catch (ChampServiceException e) { + response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + LoggingUtil.logInternalError(logger, e); + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "PUT", Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java new file mode 100644 index 0000000..af2ab20 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java @@ -0,0 +1,327 @@ +/** + * ============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 and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.async; + +import java.util.Optional; +import java.util.TimerTask; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import javax.naming.OperationNotSupportedException; +import javax.ws.rs.core.Response.Status; + +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.ChampRESTAPI; +import org.onap.champ.event.GraphEvent; +import org.onap.champ.event.GraphEvent.GraphEventResult; +import org.onap.champ.event.GraphEventEdge; +import org.onap.champ.event.GraphEventVertex; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.service.ChampDataService; +import org.onap.champ.service.ChampThreadFactory; +import org.onap.champ.service.logging.ChampMsgs; + +import org.onap.aai.event.api.EventConsumer; + +/** + * This Class polls the Graph events from request topic perform the necessary + * CRUD operation by calling champDAO and queues up the response to be consumed + * by response handler. + */ +public class ChampAsyncRequestProcessor extends TimerTask { + + private Logger logger = LoggerFactory.getInstance().getLogger(ChampAsyncRequestProcessor.class); + + private ChampDataService champDataService; + + /** + * Number of events that can be queued up. + */ + private Integer requestProcesserQueueSize; + + /** + * Number of event publisher worker threads. + */ + private Integer requestProcesserPoolSize; + + /** + * Number of event publisher worker threads. + */ + private Integer requestPollingTimeSeconds; + + /** + * Internal queue where outgoing events will be buffered until they can be + * serviced by. + **/ + private BlockingQueue<GraphEvent> requestProcesserEventQueue; + + /** + * Pool of worker threads that do the work of publishing the events to the + * event bus. + */ + private ThreadPoolExecutor requestProcesserPool; + + private ChampAsyncResponsePublisher champAsyncResponsePublisher; + + private EventConsumer asyncRequestConsumer; + + private static final Integer DEFAULT_ASYNC_REQUEST_PROCESS_QUEUE_CAPACITY = 10000; + + private static final Integer DEFAULT_ASYNC_REQUEST_PROCESS_THREAD_POOL_SIZE = 10; + private static final Integer DEFAULT_ASYNC_REQUEST_PROCESS_POLLING_SECOND = 30000; + private static final String CHAMP_GRAPH_REQUEST_PROCESS_THREAD_NAME = "ChampAsyncGraphRequestEventProcessor"; + Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(ChampRESTAPI.class.getName()); + + public ChampAsyncRequestProcessor(ChampDataService champDataService, + ChampAsyncResponsePublisher champAsyncResponsePublisher, EventConsumer asyncRequestConsumer) { + + this.requestProcesserQueueSize = DEFAULT_ASYNC_REQUEST_PROCESS_QUEUE_CAPACITY; + + this.requestProcesserPoolSize = DEFAULT_ASYNC_REQUEST_PROCESS_THREAD_POOL_SIZE; + + this.requestPollingTimeSeconds = DEFAULT_ASYNC_REQUEST_PROCESS_POLLING_SECOND; + requestProcesserEventQueue = new ArrayBlockingQueue<GraphEvent>(requestProcesserQueueSize); + requestProcesserPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(requestProcesserPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_REQUEST_PROCESS_THREAD_NAME)); + + for (int i = 0; i < requestProcesserPoolSize; i++) { + requestProcesserPool.submit(new ChampProcessorWorker()); + } + + this.champDataService = champDataService; + this.champAsyncResponsePublisher = champAsyncResponsePublisher; + this.asyncRequestConsumer = asyncRequestConsumer; + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "ChampAsyncRequestProcessor initialized SUCCESSFULLY! with event consumer " + + asyncRequestConsumer.getClass().getName()); + } + + + + public ChampAsyncRequestProcessor(ChampDataService champDataService, + ChampAsyncResponsePublisher champAsyncResponsePublisher, EventConsumer asyncRequestConsumer, + Integer requestProcesserQueueSize, Integer requestProcesserPoolSize, Integer requestPollingTimeSeconds) { + + this.requestProcesserQueueSize = requestProcesserQueueSize; + + this.requestProcesserPoolSize = requestProcesserPoolSize; + + this.requestPollingTimeSeconds = requestPollingTimeSeconds; + + requestProcesserEventQueue = new ArrayBlockingQueue<GraphEvent>(requestProcesserQueueSize); + requestProcesserPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(requestProcesserPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_REQUEST_PROCESS_THREAD_NAME)); + + for (int i = 0; i < requestProcesserPoolSize; i++) { + requestProcesserPool.submit(new ChampProcessorWorker()); + } + + this.champDataService = champDataService; + this.champAsyncResponsePublisher = champAsyncResponsePublisher; + this.asyncRequestConsumer = asyncRequestConsumer; + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "ChampAsyncRequestProcessor initialized SUCCESSFULLY! with event consumer " + + asyncRequestConsumer.getClass().getName()); + } + + private class ChampProcessorWorker implements Runnable { + + @Override + public void run() { + + while (true) { + + GraphEvent event = null; + try { + // Get the next event to be published from the queue. + event = requestProcesserEventQueue.take(); + } catch (InterruptedException e) { + // Restore the interrupted status. + Thread.currentThread().interrupt(); + } + + // Parse the event and call champ Dao to process , Create the + // response event and put it on response queue + event.setResult(GraphEventResult.SUCCESS); + + // Check if this request is part of an ongoing DB transaction + ChampTransaction transaction = champDataService.getTransaction(event.getDbTransactionId()); + if ( (event.getDbTransactionId() != null) && (transaction == null) ) { + event.setResult(GraphEventResult.FAILURE); + event.setErrorMessage("Database transactionId " + event.getDbTransactionId() + " not found"); + event.setHttpErrorStatus(Status.BAD_REQUEST); + } + + if (event.getResult() != GraphEventResult.FAILURE) { + try { + if (event.getVertex() != null) { + + switch (event.getOperation()) { + case CREATE: + event.setVertex(GraphEventVertex.fromChampObject( + champDataService.storeObject(event.getVertex().toChampObject(), Optional.ofNullable(transaction)), + event.getVertex().getModelVersion())); + break; + + case UPDATE: + event.setVertex(GraphEventVertex.fromChampObject( + champDataService.replaceObject(event.getVertex().toChampObject(), event.getVertex().getId(), Optional.ofNullable(transaction)), + event.getVertex().getModelVersion())); + break; + case DELETE: + champDataService.deleteObject(event.getVertex().getId(), Optional.ofNullable(transaction)); + break; + default: + // log error + } + } else if (event.getEdge() != null) { + switch (event.getOperation()) { + case CREATE: + event.setEdge(GraphEventEdge.fromChampRelationship( + champDataService.storeRelationship(event.getEdge().toChampRelationship(), Optional.ofNullable(transaction)), + event.getEdge().getModelVersion())); + break; + + case UPDATE: + event.setEdge(GraphEventEdge.fromChampRelationship(champDataService + .updateRelationship(event.getEdge().toChampRelationship(), event.getEdge().getId(), Optional.ofNullable(transaction)), + event.getEdge().getModelVersion())); + + break; + case DELETE: + champDataService.deleteRelationship(event.getEdge().getId(), Optional.ofNullable(transaction)); + break; + default: + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + "Invalid operation for event transactionId: " + event.getTransactionId()); + } + + } else { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + "Invalid payload for event transactionId: " + event.getTransactionId()); + } + } catch (ChampServiceException champException) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, champException.getMessage()); + event.setResult(GraphEventResult.FAILURE); + event.setErrorMessage(champException.getMessage()); + event.setHttpErrorStatus(champException.getHttpStatus()); + + } catch (Exception ex) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, ex.getMessage()); + event.setResult(GraphEventResult.FAILURE); + event.setErrorMessage(ex.getMessage()); + event.setHttpErrorStatus(Status.INTERNAL_SERVER_ERROR); + } + } + + if (event.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event processed of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult()); + } else { + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event processed of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult() + " , error: " + + event.getErrorMessage()); + } + + champAsyncResponsePublisher.publishResponseEvent(event); + + } + } + } + + @Override + public void run() { + + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, "Listening for graph events"); + + if (asyncRequestConsumer == null) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, "Unable to initialize ChampAsyncRequestProcessor"); + } + + Iterable<String> events = null; + try { + events = asyncRequestConsumer.consume(); + } catch (Exception e) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, e.getMessage()); + return; + } + + if (events == null || !events.iterator().hasNext()) { + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, "No events recieved"); + + } + + for (String event : events) { + try { + GraphEvent requestEvent = GraphEvent.fromJson(event); + auditLogger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event received of type: " + requestEvent.getObjectType() + " with key: " + requestEvent.getObjectKey() + + " , transaction-id: " + requestEvent.getTransactionId() + " , operation: " + + requestEvent.getOperation().toString()); + logger.info(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + "Event received of type: " + requestEvent.getObjectType() + " with key: " + requestEvent.getObjectKey() + + " , transaction-id: " + requestEvent.getTransactionId() + " , operation: " + + requestEvent.getOperation().toString()); + logger.debug(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, "Event received with payload:" + event); + + // Try to submit the event to be published to the event bus. + if (!requestProcesserEventQueue.offer(requestEvent)) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + "Event could not be published to the event bus due to: Internal buffer capacity exceeded."); + } + + } catch (Exception e) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, e.getMessage()); + } + } + + try { + asyncRequestConsumer.commitOffsets(); + } catch(OperationNotSupportedException e) { + //Dmaap doesnt support commit with offset + logger.debug(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_WARN, e.getMessage()); + } + catch (Exception e) { + logger.error(ChampMsgs.CHAMP_ASYNC_REQUEST_PROCESSOR_WARN, e.getMessage()); + } + + } + + + + public Integer getRequestPollingTimeSeconds() { + return requestPollingTimeSeconds; + } + + +} diff --git a/champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java new file mode 100644 index 0000000..8c31a53 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java @@ -0,0 +1,160 @@ +/** + * ============LICENSE_START======================================================= + * + * ================================================================================ + * 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 and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.async; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.event.GraphEvent; +import org.onap.champ.event.GraphEvent.GraphEventResult; +import org.onap.champ.service.ChampThreadFactory; +import org.onap.champ.service.logging.ChampMsgs; + +import org.onap.aai.event.api.EventPublisher; + +public class ChampAsyncResponsePublisher { + + private EventPublisher asyncResponsePublisher; + + /** + * Number of events that can be queued up. + */ + private Integer responsePublisherQueueSize; + + /** + * Number of event publisher worker threads. + */ + private Integer responsePublisherPoolSize; + + /** + * Internal queue where outgoing events will be buffered. + **/ + private BlockingQueue<GraphEvent> responsePublisherEventQueue; + + /** + * Pool of worker threads that do the work of publishing the events to the + * event bus. + */ + private ThreadPoolExecutor responsePublisherPool; + + private static final Integer DEFAULT_ASYNC_RESPONSE_PUBLISH_QUEUE_CAPACITY = 10000; + + private static final Integer DEFAULT_ASYNC_RESPONSE_PUBLISH_THREAD_POOL_SIZE = 10; + private static final String CHAMP_GRAPH_RESPONSE_PUBLISH_THREAD_NAME = "ChampAsyncGraphResponseEventPublisher"; + + private static Logger logger = LoggerFactory.getInstance().getLogger(ChampAsyncRequestProcessor.class.getName()); + + public ChampAsyncResponsePublisher(EventPublisher asyncResponsePublisher, Integer responsePublisherQueueSize, + Integer responsePublisherPoolSize) { + this.responsePublisherQueueSize = responsePublisherQueueSize; + + this.responsePublisherPoolSize = responsePublisherPoolSize; + + responsePublisherEventQueue = new ArrayBlockingQueue<GraphEvent>(responsePublisherQueueSize); + responsePublisherPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(responsePublisherPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_RESPONSE_PUBLISH_THREAD_NAME)); + + for (int i = 0; i < responsePublisherPoolSize; i++) { + responsePublisherPool.submit(new GizmoResponsePublisherWorker()); + } + this.asyncResponsePublisher = asyncResponsePublisher; + + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "ChampAsyncResponsePublisher initialized SUCCESSFULLY! with event publisher " + + asyncResponsePublisher.getClass().getName()); + } + + public ChampAsyncResponsePublisher(EventPublisher asyncResponsePublisher) { + responsePublisherQueueSize = DEFAULT_ASYNC_RESPONSE_PUBLISH_QUEUE_CAPACITY; + + responsePublisherPoolSize = DEFAULT_ASYNC_RESPONSE_PUBLISH_THREAD_POOL_SIZE; + + responsePublisherEventQueue = new ArrayBlockingQueue<GraphEvent>(responsePublisherQueueSize); + responsePublisherPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(responsePublisherPoolSize, + new ChampThreadFactory(CHAMP_GRAPH_RESPONSE_PUBLISH_THREAD_NAME)); + + for (int i = 0; i < responsePublisherPoolSize; i++) { + responsePublisherPool.submit(new GizmoResponsePublisherWorker()); + } + this.asyncResponsePublisher = asyncResponsePublisher; + + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "CrudAsyncResponsePublisher initialized SUCCESSFULLY! with event publisher " + + asyncResponsePublisher.getClass().getName()); + } + + public void publishResponseEvent(GraphEvent event) { + responsePublisherEventQueue.offer(event); + + } + + private class GizmoResponsePublisherWorker implements Runnable { + + @Override + public void run() { + + while (true) { + + GraphEvent event = null; + try { + + // Get the next event to be published from the queue. + event = responsePublisherEventQueue.take(); + + } catch (InterruptedException e) { + + // Restore the interrupted status. + Thread.currentThread().interrupt(); + } + // Publish the response + + try { + event.setTimestamp(System.currentTimeMillis()); + asyncResponsePublisher.sendSync(event.toJson()); + if (event.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "Response published for Event of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult()); + } else { + logger.info(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + "Response published for Event of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString() + " , result: " + event.getResult() + " , error: " + + event.getErrorMessage()); + } + } catch (Exception ex) { + logger.error(ChampMsgs.CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR, ex.getMessage()); + } + + } + } + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java new file mode 100644 index 0000000..cee7763 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java @@ -0,0 +1,67 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * 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.champ.entity; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.onap.aai.champcore.model.ChampObject; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +public class ChampObjectDeserializer extends StdDeserializer<ChampObject> { + + private static final long serialVersionUID = -3625275249560680339L; + + public ChampObjectDeserializer() { + this(null); + } + + protected ChampObjectDeserializer(Class<ChampObject> t) { + super(t); + } + + public ChampObject deserialize(JsonParser jparser, DeserializationContext dctx) + throws IOException, JsonProcessingException { + + JsonNode node = jparser.getCodec().readTree(jparser); + JsonNode type = node.get("type"); + JsonNode key = node.get("key"); + Map<String, Object> props = new HashMap<>(); + JsonNode propNode = node.get("properties"); + propNode.fields().forEachRemaining((x)->props.put(x.getKey(), x.getValue().asText())); + + ChampObject.Builder builder = new ChampObject.Builder(type.asText()).properties(props); + + if(key != null){ + builder.key(key.asText()); + } + + return builder.build(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.java new file mode 100644 index 0000000..c43b6bf --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * 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.champ.entity; + +import java.io.IOException; + +import org.onap.aai.champcore.model.ChampObject; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +public class ChampObjectSerializer extends StdSerializer<ChampObject> { + + private static final long serialVersionUID = -4057960968983473983L; + + public ChampObjectSerializer() { + this(null); + } + + protected ChampObjectSerializer(Class<ChampObject> t) { + super(t); + } + + public void serialize(ChampObject co, JsonGenerator jgen, SerializerProvider ser) + throws IOException, JsonGenerationException { + jgen.writeStartObject(); + jgen.writeStringField("key", co.getKeyValue().toString()); + jgen.writeStringField("type", co.getType()); + jgen.writeObjectField("properties", co.getProperties()); + jgen.writeEndObject(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.java new file mode 100644 index 0000000..63b9e0c --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.java @@ -0,0 +1,73 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * 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.champ.entity; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; + +public class ChampRelationshipDeserializer extends StdDeserializer<ChampRelationship> { + + private static final long serialVersionUID = -3625275249560680339L; + + public ChampRelationshipDeserializer() { + this(null); + } + + protected ChampRelationshipDeserializer(Class<ChampRelationship> t) { + super(t); + } + + public ChampRelationship deserialize(JsonParser jparser, DeserializationContext dctx) + throws IOException, JsonProcessingException { + + JsonNode node = jparser.getCodec().readTree(jparser); + JsonNode type = node.get("type"); + JsonNode key = node.get("key"); + Map<String, Object> props = new HashMap<>(); + JsonNode propNode = node.get("properties"); + propNode.fields().forEachRemaining((x)->props.put(x.getKey(), x.getValue().asText())); + + JsonNode srcNode = node.get("source"); + JsonNode targetNode = node.get("target"); + + ChampObject src = jparser.getCodec ().treeToValue ( srcNode, ChampObject.class ); + ChampObject target = jparser.getCodec ().treeToValue ( targetNode, ChampObject.class ); + + ChampRelationship.Builder builder = new ChampRelationship.Builder(src, target, type.asText()).properties(props); + + if(key != null){ + builder.key(key.asText()); + } + + return builder.build(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.java b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.java new file mode 100644 index 0000000..5d21aa5 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.java @@ -0,0 +1,55 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * 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.champ.entity; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.onap.aai.champcore.model.ChampRelationship; + +import java.io.IOException; + +public class ChampRelationshipSerializer extends StdSerializer<ChampRelationship> { + + private static final long serialVersionUID = -4057960968983473983L; + + public ChampRelationshipSerializer() { + this(null); + } + + protected ChampRelationshipSerializer(Class<ChampRelationship> t) { + super(t); + } + + public void serialize( ChampRelationship cr, JsonGenerator jgen, SerializerProvider ser) + throws IOException, JsonGenerationException { + jgen.writeStartObject(); + jgen.writeStringField("key", cr.getKeyValue().toString()); + jgen.writeStringField("type", cr.getType()); + jgen.writeObjectField("properties", cr.getProperties()); + jgen.writeObjectField ("source", cr.getSource()); + jgen.writeObjectField ("target", cr.getTarget ()); + jgen.writeEndObject(); + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/event/GraphEvent.java b/champ-service/src/main/java/org/onap/champ/event/GraphEvent.java new file mode 100644 index 0000000..d649a3e --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/event/GraphEvent.java @@ -0,0 +1,245 @@ +/** + * ============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 and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.event; + +import javax.ws.rs.core.Response.Status; + +import org.onap.champ.exception.ChampServiceException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; + +public class GraphEvent { + + public enum GraphEventOperation { + CREATE, UPDATE, DELETE + } + + public enum GraphEventResult { + SUCCESS, FAILURE + } + + private GraphEventOperation operation; + + @SerializedName("transaction-id") + private String transactionId; + + @SerializedName("database-transaction-id") + private String dbTransactionId; + + private long timestamp; + + private GraphEventVertex vertex; + + private GraphEventEdge edge; + + private GraphEventResult result; + + @SerializedName("error-message") + private String errorMessage; + + private Status httpErrorStatus; + + /** + * Marshaller/unmarshaller for converting to/from JSON. + */ + private static final Gson gson = new GsonBuilder().disableHtmlEscaping() + .setPrettyPrinting().create(); + + public static Builder builder(GraphEventOperation operation) { + return new Builder(operation); + } + + public GraphEventOperation getOperation() { + return operation; + } + + public String getTransactionId() { + return transactionId; + } + + public String getDbTransactionId() { + return dbTransactionId; + } + + public void setDbTransactionId(String id) { + dbTransactionId = id; + } + + public long getTimestamp() { + return timestamp; + } + + public GraphEventVertex getVertex() { + return vertex; + } + + public GraphEventEdge getEdge() { + return edge; + } + + public GraphEventResult getResult() { + return result; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setResult(GraphEventResult result) { + this.result = result; + } + + + public Status getHttpErrorStatus() { + return httpErrorStatus; + } + + public void setHttpErrorStatus(Status httpErrorStatus) { + this.httpErrorStatus = httpErrorStatus; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public void setVertex(GraphEventVertex vertex) { + this.vertex = vertex; + } + + public void setEdge(GraphEventEdge edge) { + this.edge = edge; + } + + /** + * Unmarshalls this Vertex object into a JSON string. + * + * @return - A JSON format string representation of this Vertex. + */ + public String toJson() { + return gson.toJson(this); + } + + /** + * Marshalls the provided JSON string into a Vertex object. + * + * @param json - The JSON string to produce the Vertex from. + * @return - A Vertex object. + * @throws SpikeException + */ + public static GraphEvent fromJson(String json) throws ChampServiceException { + + try { + + // Make sure that we were actually provided a non-empty string + // before we + // go any further. + if (json == null || json.isEmpty()) { + throw new ChampServiceException("Empty or null JSON string.", Status.BAD_REQUEST); + } + + // Marshall the string into a Vertex object. + return gson.fromJson(json, GraphEvent.class); + + } catch (Exception ex) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + } + + @Override + public String toString() { + + return toJson(); + } + + public String getObjectKey() { + if (this.getVertex() != null) { + return this.getVertex().getId(); + } else if (this.getEdge() != null) { + return this.getEdge().getId(); + } + + return null; + } + + public String getObjectType() { + if (this.getVertex() != null) { + return "vertex->" + this.getVertex().getType(); + } else if (this.getEdge() != null) { + return "edge->" + this.getEdge().getType(); + } + + return null; + } + + public static class Builder { + + GraphEvent event = null; + + public Builder(GraphEventOperation operation) { + event = new GraphEvent(); + event.operation = operation; + } + + public Builder vertex(GraphEventVertex vertex) { + event.vertex = vertex; + return this; + } + + public Builder edge(GraphEventEdge edge) { + event.edge = edge; + return this; + } + + public Builder result(GraphEventResult result) { + event.result = result; + return this; + } + + public Builder errorMessage(String errorMessage) { + event.errorMessage = errorMessage; + return this; + } + + public Builder httpErrorStatus(Status httpErrorStatus) { + event.httpErrorStatus = httpErrorStatus; + return this; + } + + public GraphEvent build() { + + event.timestamp = System.currentTimeMillis(); + event.transactionId = java.util.UUID.randomUUID().toString(); + + return event; + } + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java b/champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java new file mode 100644 index 0000000..1ab4804 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java @@ -0,0 +1,221 @@ +/** + * ============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 and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.event; + +import java.util.Map; + +import javax.ws.rs.core.Response.Status; + +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.champ.exception.ChampServiceException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +/** + * This class provides a generic representation of an Edge as provided by the + * graph data store. + */ +public class GraphEventEdge { + + /** + * The unique identifier used to identify this edge in the graph data store. + */ + @SerializedName("key") + private String id; + + @SerializedName("schema-version") + private String modelVersion; + + /** + * Type label assigned to this vertex. + */ + private String type; + + /** + * Source vertex for our edge. + */ + private GraphEventVertex source; + + /** + * Target vertex for our edge. + */ + private GraphEventVertex target; + + /** + * Map of all of the properties assigned to this vertex. + */ + private JsonElement properties; + + /** + * Marshaller/unmarshaller for converting to/from JSON. + */ + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + public GraphEventEdge(String id, String modelVersion, String type, GraphEventVertex source, + GraphEventVertex target, JsonElement properties) { + this.id = id; + this.modelVersion = modelVersion; + this.type = type; + this.source = source; + this.target = target; + this.properties = properties; + } + + public GraphEventEdge() { + + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public GraphEventVertex getSource() { + return source; + } + + public void setSource(GraphEventVertex source) { + this.source = source; + } + + public GraphEventVertex getTarget() { + return target; + } + + public void setTarget(GraphEventVertex target) { + this.target = target; + } + + public JsonElement getProperties() { + return properties; + } + + public void setProperties(JsonElement properties) { + this.properties = properties; + } + + public String getModelVersion() { + return modelVersion; + } + + public void setModelVersion(String modelVersion) { + this.modelVersion = modelVersion; + } + + /** + * Unmarshalls this Edge object into a JSON string. + * + * @return - A JSON format string representation of this Edge. + */ + public String toJson() { + return gson.toJson(this); + } + + /** + * Marshalls the provided JSON string into a Edge object. + * + * @param json - The JSON string to produce the Edge from. + * @return - A Edge object. + * @throws SpikeException + */ + public static GraphEventEdge fromJson(String json) throws ChampServiceException { + + try { + + // Make sure that we were actually provided a non-empty string + // before we + // go any further. + if (json == null || json.isEmpty()) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + + // Marshall the string into an Edge object. + return gson.fromJson(json, GraphEventEdge.class); + + } catch (Exception ex) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + } + + public static GraphEventEdge fromChampRelationship(ChampRelationship edge, String modelVersion) { + + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + JsonObject props = gson.toJsonTree(edge.getProperties(), mapType).getAsJsonObject(); + + GraphEventEdge graphEventEdge = new GraphEventEdge(edge.getKey().orElse("").toString(), modelVersion, + edge.getType(), new GraphEventVertex(edge.getSource().getKey().orElse("").toString(), null, + edge.getSource().getType(), null), new GraphEventVertex(edge.getTarget().getKey().orElse("").toString(), + null, edge.getTarget().getType(), null), props); + + return graphEventEdge; + + } + + public ChampRelationship toChampRelationship() { + ChampObject sourceChampObject=null; + ChampObject targetChampObject=null; + if (this.getSource() != null) { + sourceChampObject = new ChampObject.Builder(this.getSource().getType()).key(this.getSource().getId()) + .build(); + } + if (this.getTarget() != null) { + targetChampObject = new ChampObject.Builder(this.getTarget().getType()).key(this.getTarget().getId()) + .build(); + } + + ChampRelationship.Builder builder = new ChampRelationship.Builder(sourceChampObject, targetChampObject, type); + if(this.getId()!=null && !this.getId().isEmpty()){ + builder.key(this.getId()); + } + + + if (this.getProperties() != null) { + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + Map<String, Object> propertiesMap = gson.fromJson(this.getProperties(), mapType); + for (String key : propertiesMap.keySet()) { + builder.property(key, propertiesMap.get(key)); + } + } + return builder.build(); + + } +} diff --git a/champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java b/champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java new file mode 100644 index 0000000..553ba46 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java @@ -0,0 +1,187 @@ +/** + * ============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 and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.event; + +import java.util.Map; + +import javax.ws.rs.core.Response.Status; + +import org.onap.aai.champcore.model.ChampObject; +import org.onap.champ.exception.ChampServiceException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +/** + * This class provides a generic representation of a Vertex as provided by the + * graph data store. + */ +public class GraphEventVertex { + + /** + * The unique identifier used to identify this vertex in the graph data + * store. + */ + @SerializedName("key") + private String id; + + @SerializedName("schema-version") + private String modelVersion; + + /** + * Type label assigned to this vertex. + */ + private String type; + + /** + * Map of all of the properties assigned to this vertex. + */ + private JsonElement properties; + + /** + * Marshaller/unmarshaller for converting to/from JSON. + */ + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + public GraphEventVertex(String id, String modelVersion, String type, JsonElement properties) { + this.id = id; + this.modelVersion = modelVersion; + this.type = type; + this.properties = properties; + } + + public GraphEventVertex() { + + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + + public JsonElement getProperties() { + return properties; + } + + public void setProperties(JsonElement properties) { + this.properties = properties; + } + + public String getModelVersion() { + return modelVersion; + } + + public void setModelVersion(String modelVersion) { + this.modelVersion = modelVersion; + } + + /** + * Unmarshalls this Vertex object into a JSON string. + * + * @return - A JSON format string representation of this Vertex. + */ + public String toJson() { + return gson.toJson(this); + } + + /** + * Marshalls the provided JSON string into a Vertex object. + * + * @param json - The JSON string to produce the Vertex from. + * @return - A Vertex object. + * @throws SpikeException + */ + public static GraphEventVertex fromJson(String json) throws ChampServiceException { + + try { + + // Make sure that we were actually provided a non-empty string + // before we + // go any further. + if (json == null || json.isEmpty()) { + throw new ChampServiceException("Empty or null JSON string.", Status.BAD_REQUEST); + } + + // Marshall the string into a Vertex object. + return gson.fromJson(json, GraphEventVertex.class); + + } catch (Exception ex) { + throw new ChampServiceException("Unable to parse JSON string: ", Status.BAD_REQUEST); + } + } + + @Override + public String toString() { + + return toJson(); + } + + + public static GraphEventVertex fromChampObject(ChampObject champObject, String modelVersion) { + + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + JsonObject props = gson.toJsonTree(champObject.getProperties(), mapType).getAsJsonObject(); + GraphEventVertex graphEventVertex = new GraphEventVertex(champObject.getKey().orElse("").toString(), + modelVersion, champObject.getType(), props); + return graphEventVertex; + + } + + + public ChampObject toChampObject() { + ChampObject.Builder builder = new ChampObject.Builder(this.getType()); + if(this.getId()!=null && !this.getId().isEmpty()){ + builder.key(this.getId()); + } + + if (this.getProperties() != null) { + java.lang.reflect.Type mapType = new TypeToken<Map<String, Object>>() {}.getType(); + Map<String, Object> propertiesMap = gson.fromJson(this.getProperties(), mapType); + for (String key : propertiesMap.keySet()) { + builder.property(key, propertiesMap.get(key)); + } + } + + return builder.build(); + + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java b/champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java new file mode 100644 index 0000000..6e5e8c2 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java @@ -0,0 +1,62 @@ +/** + * ============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.champ.exception; + +import javax.ws.rs.core.Response.Status; + +public class ChampServiceException extends Exception { + + private static final long serialVersionUID = 8162385108397238865L; + + private Status httpStatus; + + public ChampServiceException() { + } + + public ChampServiceException(String message, Status httpStatus) { + super(message); + this.setHttpStatus(httpStatus); + } + + public ChampServiceException(Throwable cause) { + super(cause); + } + + public ChampServiceException(String message, Throwable cause) { + super(message, cause); + } + + public ChampServiceException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public Status getHttpStatus() { + return httpStatus; + } + + public void setHttpStatus(Status httpStatus) { + this.httpStatus = httpStatus; + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampDataService.java b/champ-service/src/main/java/org/onap/champ/service/ChampDataService.java new file mode 100644 index 0000000..7826fa2 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampDataService.java @@ -0,0 +1,355 @@ +package org.onap.champ.service; + +import org.onap.aai.champcore.ChampGraph; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampMarshallingException; +import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException; +import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException; +import org.onap.aai.champcore.exceptions.ChampSchemaViolationException; +import org.onap.aai.champcore.exceptions.ChampTransactionException; +import org.onap.aai.champcore.exceptions.ChampUnmarshallingException; +import org.onap.aai.champcore.model.ChampElement; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.service.logging.ChampMsgs; +import org.onap.champ.util.ChampProperties; +import org.onap.champ.util.ChampServiceConstants; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.ws.rs.core.Response.Status; + +public class ChampDataService { + private ChampUUIDService champUUIDService; + + private ChampGraph graphImpl; + private ChampTransactionCache cache; + private static final String KEY_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_KEY_NAME); + private static final String SOT_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_SOT_NAME); + private static final String CREATED_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_CREATED_TS_NAME); + private static final String LAST_MOD_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_LAST_MOD_TS_NAME); + private Logger logger = LoggerFactory.getInstance().getLogger(ChampDataService.class); + + + public ChampDataService(ChampUUIDService champUUIDService, ChampGraph graphImpl, ChampTransactionCache cache) { + + this.champUUIDService = champUUIDService; + this.graphImpl = graphImpl; + this.cache = cache; + } + + public ChampObject getObject(String id, Optional<ChampTransaction> transaction) throws ChampServiceException { + + Optional<ChampObject> retrieved = Optional.empty(); + try { + retrieved = champUUIDService.getObjectbyUUID(id, transaction.orElse(null)); + } catch (ChampUnmarshallingException | ChampTransactionException e) { + throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR); + } + if (retrieved.isPresent()) { + return (ChampObject) champUUIDService.populateUUIDKey(retrieved.get()); + } else { + return null; + } + } + + public ChampObject storeObject(ChampObject object, Optional<ChampTransaction> transaction) + throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException, + ChampTransactionException, ChampServiceException { + + if (object.getProperty(KEY_NAME).isPresent() || object.getKey().isPresent()) { + throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST); + } + + champUUIDService.populateUUIDProperty(object, java.util.UUID.randomUUID().toString()); + addTimestamps(object, null); + ChampObject created = graphImpl.storeObject(object, transaction); + return (ChampObject) champUUIDService.populateUUIDKey(created); + } + + public ChampObject replaceObject(ChampObject object, String objectId, Optional<ChampTransaction> transaction) + throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException, + ChampSchemaViolationException, ChampObjectNotExistsException { + if (object.getKey().isPresent() && (!object.getKeyValue().equals(objectId))) { + throw new ChampServiceException("Object Id in the URI doesn't match the body.", Status.BAD_REQUEST); + } + + if (object.getProperty(KEY_NAME).isPresent() && !object.getProperty(KEY_NAME).get().toString().equals(objectId)) { + throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST); + } + + Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND); + } + ObjectBuildOrPropertiesStep payloadBuilder = ChampObject.create().from(object).withKey(retrieved.get().getKey().get()) + .withProperty(KEY_NAME, objectId); + if (retrieved.get().getProperty(SOT_NAME).isPresent()){ + payloadBuilder = payloadBuilder.withProperty(SOT_NAME, retrieved.get().getProperty(SOT_NAME).get()); + } + + if (object.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) { + // the timestamps in object are parsed as strings regardless of how the input json is. Convert retrieved to string for easy comparison + if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(object.getProperty(CREATED_TS_NAME).get())) { + throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + if (object.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) { + if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(object.getProperty(LAST_MOD_TS_NAME).get())) { + throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + ChampObject payload = payloadBuilder.build(); + addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null)); + ChampObject updated = graphImpl.replaceObject(payload, transaction); + return (ChampObject) champUUIDService.populateUUIDKey(updated); + } + + public void deleteObject(String objectId, Optional<ChampTransaction> transaction) throws ChampServiceException, + ChampObjectNotExistsException, ChampTransactionException, ChampUnmarshallingException { + Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND); + } + Stream<ChampRelationship> relationships = graphImpl.retrieveRelationships(retrieved.get(), transaction); + + if (relationships.count() > 0) { + throw new ChampServiceException("Attempt to delete vertex with id " + objectId + " which has incident edges.", + Status.BAD_REQUEST); + } + graphImpl.deleteObject(retrieved.get().getKey().get(), transaction); + + } + + public ChampRelationship storeRelationship(ChampRelationship r, Optional<ChampTransaction> transaction) + throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException, + ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException, + ChampServiceException { + + if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null + || !r.getTarget().getKey().isPresent()) { + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target Object key must be provided"); + throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST); + } + + if (r.getProperty(KEY_NAME).isPresent() || r.getKey().isPresent()) { + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "key or " + KEY_NAME + " not allowed while creating new Objects"); + throw new ChampServiceException("key or " + KEY_NAME + " not allowed while creating new Objects", Status.BAD_REQUEST); + + } + + Optional<ChampObject> source = champUUIDService.getObjectbyUUID(r.getSource().getKey().get().toString(), + transaction.orElse(null)); + Optional<ChampObject> target = champUUIDService.getObjectbyUUID(r.getTarget().getKey().get().toString(), + transaction.orElse(null)); + + if (!source.isPresent() || !target.isPresent()) { + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target object not found"); + throw new ChampServiceException("Source/Target object not found", Status.BAD_REQUEST); + } + + champUUIDService.populateUUIDProperty(r, java.util.UUID.randomUUID().toString()); + + ChampRelationship payload = new ChampRelationship.Builder(source.get(), target.get(), r.getType()) + .properties(r.getProperties()).build(); + addTimestamps(payload, null); + ChampRelationship created = graphImpl.storeRelationship(payload, transaction); + return (ChampRelationship) champUUIDService.populateUUIDKey(created); + } + + public ChampRelationship updateRelationship(ChampRelationship r, String rId, Optional<ChampTransaction> transaction) + throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException, + ChampSchemaViolationException, ChampRelationshipNotExistsException { + if (r.getKey().isPresent() && (!r.getKeyValue().equals(rId))) { + + throw new ChampServiceException("Relationship Id in the URI \"" + rId + "\" doesn't match the URI in the body" + + " \"" + r.getKeyValue() + "\"", Status.BAD_REQUEST); + + } + + if (r.getProperty(KEY_NAME).isPresent() && !r.getProperty(KEY_NAME).get().toString().equals(rId)) { + throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST); + } + + Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(rId, transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(rId + " not found", Status.NOT_FOUND); + } + // check if key is present or if it equals the key that is in the URI + if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null + || !r.getTarget().getKey().isPresent()) { + throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST); + } + ChampObject source = retrieved.get().getSource(); + ChampObject target = retrieved.get().getTarget(); + + if (!source.getProperty(KEY_NAME).get().toString().equals(r.getSource().getKey().get().toString()) + || !target.getProperty(KEY_NAME).get().toString().equals(r.getTarget().getKey().get().toString())) { + throw new ChampServiceException("Source/Target cannot be updated", Status.BAD_REQUEST); + } + + if (r.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) { + if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(r.getProperty(CREATED_TS_NAME).get())) { + throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + if (r.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) { + if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(r.getProperty(LAST_MOD_TS_NAME).get())) { + throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST); + } + } + + ChampRelationship payload = new ChampRelationship.Builder(source, target, r.getType()) + .key(retrieved.get().getKey().get()).properties(r.getProperties()).property(KEY_NAME, rId).build(); + addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null)); + ChampRelationship updated = graphImpl.replaceRelationship(payload, transaction); + return (ChampRelationship) champUUIDService.populateUUIDKey(updated); + } + + public void deleteRelationship(String relationshipId, Optional<ChampTransaction> transaction) + throws ChampServiceException, ChampRelationshipNotExistsException, ChampTransactionException, + ChampUnmarshallingException { + Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(relationshipId, + transaction.orElse(null)); + if (!retrieved.isPresent()) { + throw new ChampServiceException(relationshipId + " not found", Status.NOT_FOUND); + } + + graphImpl.deleteRelationship(retrieved.get(), transaction); + + } + + + public List<ChampRelationship> getRelationshipsByObject(String objectId, Optional<ChampTransaction> transaction) + throws ChampServiceException { + try { + Optional<ChampObject> retrievedObject = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null)); + if (!retrievedObject.isPresent()) { + throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND); + } + List<ChampRelationship> relations = new ArrayList<ChampRelationship>(); + + Stream<ChampRelationship> retrieved = graphImpl.retrieveRelationships(retrievedObject.get(), transaction); + relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList())); + return relations; + } catch (ChampObjectNotExistsException e) { + throw new ChampServiceException(" obj not found", Status.NOT_FOUND); + } catch (ChampUnmarshallingException | ChampTransactionException e) { + throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR); + } + + } + + /** + * Gets the ChampObjects that pass filter + * @param filter key/value pairs that must be present in the returned objects + * @param properties properties that will show up in the object + * @return + * @throws ChampServiceException + */ + public List<ChampObject> queryObjects(Map<String, Object> filter, HashSet<String> properties) throws ChampServiceException { + try { + + Stream<ChampObject> retrieved = graphImpl.queryObjects(filter); + List<ChampObject> objects = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList())); + + if (!properties.contains("all")) { + for (ChampObject champObject : objects) { + champObject.dropProperties(properties); + } + } + + return objects; + } catch (ChampTransactionException e) { + throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR); + } + } + + public List<ChampRelationship> queryRelationships(Map<String, Object> filter) throws ChampServiceException { + try { + List<ChampRelationship> relations = new ArrayList<ChampRelationship>(); + Stream<ChampRelationship> retrieved; + + retrieved = graphImpl.queryRelationships(filter); + + relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList())); + return relations; + } catch (ChampTransactionException e) { + throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR); + } + } + + public ChampRelationship getRelationship(String id, Optional<ChampTransaction> transaction) + throws ChampServiceException { + + Optional<ChampRelationship> retrieved = Optional.empty(); + try { + retrieved = champUUIDService.getRelationshipbyUUID(id, transaction.orElse(null)); + } catch (ChampUnmarshallingException | ChampTransactionException e) { + throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR); + } + if (retrieved.isPresent()) { + return (ChampRelationship) champUUIDService.populateUUIDKey(retrieved.get()); + } else { + return null; + } + } + + public String openTransaction() { + ChampTransaction transaction = graphImpl.openTransaction(); + String transacId = transaction.id(); + cache.put(transacId, transaction); + return transacId; + + } + + public void commitTransaction(String tId) throws ChampServiceException, ChampTransactionException { + ChampTransaction transaction = cache.get(tId); + if (transaction == null) { + throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND); + } + graphImpl.commitTransaction(transaction); + cache.invalidate(tId); + cache.invalidate(transaction.id()); + + } + + public void rollbackTransaction(String tId) throws ChampServiceException, ChampTransactionException { + ChampTransaction transaction = cache.get(tId); + if (transaction == null) { + throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND); + } + graphImpl.rollbackTransaction(transaction); + cache.invalidate(tId); + cache.invalidate(transaction.id()); + + } + + public ChampTransaction getTransaction(String id) { + return cache.get(id); + } + + private void addTimestamps(ChampElement e, Long oldCreated) { + Long timestamp = System.currentTimeMillis(); + + if (oldCreated == null) { + e.getProperties().put(CREATED_TS_NAME, timestamp); + } else { + e.getProperties().put(CREATED_TS_NAME, oldCreated); + } + + e.getProperties().put(LAST_MOD_TS_NAME, timestamp); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java b/champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java new file mode 100644 index 0000000..25fe65e --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java @@ -0,0 +1,47 @@ +/** + * ============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 and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + */ +package org.onap.champ.service; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Thread factory for workers. + */ +public class ChampThreadFactory implements ThreadFactory { + + private AtomicInteger threadNumber = new AtomicInteger(1); + + private String threadPrefix; + + + public ChampThreadFactory(String threadPrefix) { + this.threadPrefix = threadPrefix; + } + + public Thread newThread(Runnable runnable) { + return new Thread(runnable, threadPrefix + "-" + threadNumber.getAndIncrement()); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java b/champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java new file mode 100644 index 0000000..bb95147 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java @@ -0,0 +1,77 @@ + +package org.onap.champ.service; + +import java.util.concurrent.TimeUnit; + +import org.onap.aai.champcore.ChampGraph; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampTransactionException; +import org.onap.champ.service.logging.ChampMsgs; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalCause; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; + +/** + * Self expiring Cache to hold request transactionIds . Events are expired + * automatically after configured interval + */ +public class ChampTransactionCache { + private static Logger logger = LoggerFactory.getInstance().getLogger(ChampTransactionCache + .class.getName()); + + + private ChampGraph graphImpl; + private Cache<String, ChampTransaction> cache; + + + + public ChampTransactionCache(long txTimeOutInSec,ChampGraph graphImpl) { + CacheBuilder builder = CacheBuilder.newBuilder().expireAfterWrite(txTimeOutInSec, TimeUnit.SECONDS) + .removalListener(new RemovalListener() { + + public void onRemoval(RemovalNotification notification) { + if(notification.getCause()==RemovalCause.EXPIRED){ + logger.info(ChampMsgs.CHAMP_TX_CACHE, "Following transaction: "+notification.getKey()+" is being evicted from cache due to timeout of " + txTimeOutInSec+" seconds"); + try { + graphImpl.rollbackTransaction((ChampTransaction) notification.getValue()); + logger.info(ChampMsgs.CHAMP_TX_CACHE, "Transaction rolledback successfully :" + notification.getKey()); + } catch (ChampTransactionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + }); + cache = builder.build(); + + this.graphImpl = graphImpl; + + } + + public void put(String txId, ChampTransaction tx) { + cache.put(txId, tx); + + } + + public ChampTransaction get(String txId) { + if (txId==null) + return null; + if(cache.getIfPresent(txId)==null){ + //cleanup cache so that removalListener is called + cache.cleanUp(); + } + return cache.getIfPresent(txId); + } + + public void invalidate(String txId) { + cache.invalidate(txId); + } + + + +} diff --git a/champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java b/champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java new file mode 100644 index 0000000..39c775b --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java @@ -0,0 +1,115 @@ +package org.onap.champ.service; + +import org.onap.aai.champcore.ChampGraph; +import org.onap.aai.champcore.ChampTransaction; +import org.onap.aai.champcore.exceptions.ChampTransactionException; +import org.onap.aai.champcore.exceptions.ChampUnmarshallingException; +import org.onap.aai.champcore.model.ChampElement; +import org.onap.aai.champcore.model.ChampObject; +import org.onap.aai.champcore.model.ChampRelationship; +import org.onap.champ.exception.ChampServiceException; +import org.onap.champ.util.ChampProperties; +import org.onap.champ.util.ChampServiceConstants; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +public class ChampUUIDService { + private ChampGraph graphImpl; + private static final String KEY_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_KEY_NAME); + + + public ChampUUIDService(ChampGraph graphImpl) { + this.graphImpl = graphImpl; + } + + public List populateUUIDKey(List<ChampElement> elements) { + { + List response = new ArrayList(); + for (ChampElement e : elements) { + ChampElement item = populateUUIDKey(e); + if (item != null) { + response.add(item); + } + } + return response; + } + + } + + public ChampElement populateUUIDKey(ChampElement e) { + { + ChampElement response = null; + + if (e.isObject()) { + if (e.asObject().getProperty(KEY_NAME).isPresent()) { + response = (ChampObject.create().from(e.asObject()) + .withKey(e.asObject().getProperty(KEY_NAME).get().toString()).build()); + } + } else { + if (e.asRelationship().getProperty(KEY_NAME).isPresent() + && e.asRelationship().getSource().getProperty(KEY_NAME).isPresent() + && e.asRelationship().getTarget().getProperty(KEY_NAME).isPresent()) { + ChampObject source = ChampObject.create().from(e.asRelationship().getSource()) + .withKey(e.asRelationship().getSource().getProperty(KEY_NAME).get().toString()).build(); + ChampObject target = ChampObject.create().from(e.asRelationship().getTarget()) + .withKey(e.asRelationship().getTarget().getProperty(KEY_NAME).get().toString()).build(); + ChampRelationship rel = new ChampRelationship.Builder(source, target, e.asRelationship().getType()) + .key(e.asRelationship().getProperty(KEY_NAME).get().toString()) + .properties(e.asRelationship().getProperties()).build(); + response = rel; + } + + } + + return response; + } + + } + + public void populateUUIDProperty(ChampElement e, String uuid) { + e.getProperties().put(KEY_NAME, uuid); + } + + + public Optional<ChampObject> getObjectbyUUID(String uuid, ChampTransaction transaction) + throws ChampUnmarshallingException, ChampTransactionException, ChampServiceException { + Optional<ChampObject> response = Optional.empty(); + + Stream<ChampObject> s; + Map<String, Object> filter = new HashMap<>(); + filter.put(KEY_NAME, uuid); + + s = graphImpl.queryObjects(filter, Optional.ofNullable(transaction)); + Object[] objs = s.toArray(); + if (objs.length == 0) { + return response; + } + response = graphImpl.retrieveObject(((ChampObject) objs[0]).getKey().get(), Optional.ofNullable(transaction)); + return response; + } + + public Optional<ChampRelationship> getRelationshipbyUUID(String uuid, ChampTransaction transaction) + throws ChampUnmarshallingException, ChampTransactionException, ChampServiceException { + Optional<ChampRelationship> response = Optional.empty(); + + + Stream<ChampRelationship> s; + Map<String, Object> filter = new HashMap<>(); + filter.put(KEY_NAME, uuid); + + s = graphImpl.queryRelationships(filter, Optional.ofNullable(transaction)); + Object[] objs = s.toArray(); + if (objs.length == 0) { + return response; + } + response = graphImpl.retrieveRelationship(((ChampRelationship) objs[0]).getKey().get(), + Optional.ofNullable(transaction)); + return response; + } + +} diff --git a/champ-service/src/main/java/org/onap/champ/service/EchoService.java b/champ-service/src/main/java/org/onap/champ/service/EchoService.java new file mode 100644 index 0000000..c8236b1 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/EchoService.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * 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.champ.service; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +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.UriInfo; + + +public class EchoService { + + private static Logger logger = LoggerFactory.getInstance() + .getLogger(EchoService.class.getName()); + private static Logger auditLogger = LoggerFactory.getInstance() + .getAuditLogger(EchoService.class.getName()); + + @GET + @Path("echo/{input}") + @Produces("text/plain") + public String ping(@PathParam("input") String input, + @Context HttpHeaders headers, + @Context UriInfo info, + @Context HttpServletRequest req) { + + return "Hello, " + input + "."; + } +}
\ No newline at end of file diff --git a/champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java b/champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java new file mode 100644 index 0000000..2ddbff4 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java @@ -0,0 +1,130 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 Amdocs + * =================================================================== + * 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.champ.service.logging; + +import com.att.eelf.i18n.EELFResourceManager; +import org.onap.aai.cl.eelf.LogMessageEnum; + +public enum ChampMsgs implements LogMessageEnum { + + /** + * Received request {0} {1} from {2}. Sending response: {3} + * + * <p> + * Arguments: {0} = operation {1} = target URL {2} = source {3} = response + * code + */ + PROCESS_REST_REQUEST, + /** + * Processed event {0}. Result: {1}. + * + * Arguments: {0} = event {1} = result + */ + PROCESS_EVENT, + + /** + * Query: {0} + * Arguments: {0} = query + */ + QUERY, + + /** + * Arguments: {0} = transactionID, {1} = request + */ + INCOMING_REQUEST, + + /** + * Arguments: {0} = HTTP request type, {1} = time to process in milliseconds + */ + PROCESSED_REQUEST, + + /** + * Arguments: {0} = transaction ID + */ + TRANSACTION_NOT_FOUND, + + /** + * Arguments: {0} = request, {1} = Error + */ + BAD_REQUEST, + + /** + * Arguments: {0} = Info + */ + CHAMP_TX_CACHE, + + /** + * Any info log related to CHAMP_ASYNC_REQUEST_PROCESSOR_INFO + * + * <p>Arguments: + * {0} - Info. + */ + CHAMP_ASYNC_REQUEST_PROCESSOR_INFO, + CHAMP_ASYNC_REQUEST_PROCESSOR_WARN, + + /** + * Any error log related to CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR + * + * <p>Arguments: + * {0} - Error. + */ + CHAMP_ASYNC_REQUEST_PROCESSOR_ERROR, + + /** + * Any info log related to CHAMP_DATA_SERVICE_INFO + * + * <p>Arguments: + * {0} - Info. + */ + CHAMP_DATA_SERVICE_INFO, + + /** + * Any error log related to CHAMP_DATA_SERVICE_INFO + * + * <p>Arguments: + * {0} - Error. + */ + CHAMP_DATA_SERVICE_ERROR, + + + /** + * Any info log related to CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO + * + * <p>Arguments: + * {0} - Info. + */ + CHAMP_ASYNC_RESPONSE_PUBLISHER_INFO, + + /** + * Any error log related to CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR + * + * <p>Arguments: + * {0} - Error. + */ + CHAMP_ASYNC_RESPONSE_PUBLISHER_ERROR; + /** + * Static initializer to ensure the resource bundles for this class are loaded... + */ + static { + EELFResourceManager.loadMessageBundle("logging/ChampMsgs"); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java b/champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java new file mode 100644 index 0000000..b7f0e77 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java @@ -0,0 +1,92 @@ +/** + * ============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.champ.service.logging; + +import org.onap.aai.cl.api.LogFields; +import org.onap.aai.cl.api.LogLine; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.mdc.MdcContext; + +import org.slf4j.MDC; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; + +public class LoggingUtil { + /** + * Initializes mdc context. + */ + public static void initMdcContext(HttpServletRequest httpReq, HttpHeaders headers) { + String fromIp = httpReq.getRemoteAddr(); + String fromAppId = ""; + String transId = null; + + if (headers.getRequestHeaders().getFirst("X-FromAppId") != null) { + fromAppId = headers.getRequestHeaders().getFirst("X-FromAppId"); + } + + if ((headers.getRequestHeaders().getFirst("X-TransactionId") == null) + || headers.getRequestHeaders().getFirst("X-TransactionId").isEmpty()) { + transId = java.util.UUID.randomUUID().toString(); + } else { + transId = headers.getRequestHeaders().getFirst("X-TransactionId"); + } + + MdcContext.initialize(transId, "ChampService", "", fromAppId, fromIp); + } + + /** + * Logs the rest request. + */ + public static void logRestRequest(Logger logger, Logger auditLogger, HttpServletRequest req, Response response) { + String respStatusString = ""; + if (Response.Status.fromStatusCode(response.getStatus()) != null) { + respStatusString = Response.Status.fromStatusCode(response.getStatus()).toString(); + } + + // Generate error log + logger.info(ChampMsgs.PROCESS_REST_REQUEST, req.getMethod(), req.getRequestURL().toString(), + req.getRemoteHost(), Integer.toString(response.getStatus())); + + // Generate audit log. + auditLogger.info(ChampMsgs.PROCESS_REST_REQUEST, + new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, response.getStatus()) + .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, respStatusString), + (req != null) ? req.getMethod() : "Unknown", (req != null) ? req.getRequestURL().toString() : "Unknown", + (req != null) ? req.getRemoteHost() : "Unknown", Integer.toString(response.getStatus()) + " payload: " + + (response.getEntity() == null ? "" : response.getEntity().toString())); + MDC.clear(); + } + + public static void logInternalError(Logger logger, Exception ex) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Internal error: " + ex.getMessage() + "\n" + writer.toString()); + } +} diff --git a/champ-service/src/main/java/org/onap/champ/util/ChampProperties.java b/champ-service/src/main/java/org/onap/champ/util/ChampProperties.java new file mode 100644 index 0000000..178da97 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/util/ChampProperties.java @@ -0,0 +1,53 @@ +package org.onap.champ.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +public class ChampProperties { + + private static Properties properties; + + static { + properties = new Properties(); + File file = new File(ChampServiceConstants.CHAMP_CONFIG_FILE); + try { + properties.load(new FileInputStream(file)); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(1); + } + } + + public static String get(String key) { + return properties.getProperty(key); + } + + public static String get(String key, String defaultValue) { + return properties.getProperty(key, defaultValue); + } + + public static void put(String key, String value) { + properties.setProperty(key, value); + FileOutputStream fileOut = null; + try { + fileOut = new FileOutputStream(new File(ChampServiceConstants.CHAMP_CONFIG_FILE)); + properties.store(fileOut, "Added property: " + key); + } catch (Exception e) { + e.printStackTrace(); + } finally { + + try { + fileOut.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + } + + +} diff --git a/champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java b/champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java new file mode 100644 index 0000000..94a9972 --- /dev/null +++ b/champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java @@ -0,0 +1,14 @@ +package org.onap.champ.util; + +public class ChampServiceConstants { + public static final String CHAMP_FILESEP = (System.getProperty("file.separator") == null) ? "/" + : System.getProperty("file.separator"); + + public static final String CHAMP_SPECIFIC_CONFIG = System.getProperty("CONFIG_HOME") + CHAMP_FILESEP; + public static final String CHAMP_CONFIG_FILE = CHAMP_SPECIFIC_CONFIG + "champ-api.properties"; + public static final String CHAMP_KEY_NAME = "keyName"; + public static final String CHAMP_SOT_NAME = "sourceOfTruthName"; + public static final String CHAMP_CREATED_TS_NAME = "createdTsName"; + public static final String CHAMP_LAST_MOD_TS_NAME = "lastModTsName"; + public static final String CHAMP_COLLECTION_PROPERTIES_KEY = "collectionPropertiesKey"; +}
\ No newline at end of file |