aboutsummaryrefslogtreecommitdiffstats
path: root/champ-service/src/main/java/org/onap
diff options
context:
space:
mode:
authormichaere <michaere@amdocs.com>2018-03-05 16:33:32 +0000
committermichaere <michaere@amdocs.com>2018-03-07 11:17:22 +0000
commitc74f7b13b573386e70c10721fc391624ee792ed6 (patch)
treeb44995474ff938b4b03c9b234f95b71bc75d6b79 /champ-service/src/main/java/org/onap
parent9fc28cff11a4b570618c0f533ce9de6209a5dd0c (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/org/onap')
-rw-r--r--champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java568
-rw-r--r--champ-service/src/main/java/org/onap/champ/async/ChampAsyncRequestProcessor.java327
-rw-r--r--champ-service/src/main/java/org/onap/champ/async/ChampAsyncResponsePublisher.java160
-rw-r--r--champ-service/src/main/java/org/onap/champ/entity/ChampObjectDeserializer.java67
-rw-r--r--champ-service/src/main/java/org/onap/champ/entity/ChampObjectSerializer.java54
-rw-r--r--champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipDeserializer.java73
-rw-r--r--champ-service/src/main/java/org/onap/champ/entity/ChampRelationshipSerializer.java55
-rw-r--r--champ-service/src/main/java/org/onap/champ/event/GraphEvent.java245
-rw-r--r--champ-service/src/main/java/org/onap/champ/event/GraphEventEdge.java221
-rw-r--r--champ-service/src/main/java/org/onap/champ/event/GraphEventVertex.java187
-rw-r--r--champ-service/src/main/java/org/onap/champ/exception/ChampServiceException.java62
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/ChampDataService.java355
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/ChampThreadFactory.java47
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/ChampTransactionCache.java77
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/ChampUUIDService.java115
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/EchoService.java54
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/logging/ChampMsgs.java130
-rw-r--r--champ-service/src/main/java/org/onap/champ/service/logging/LoggingUtil.java92
-rw-r--r--champ-service/src/main/java/org/onap/champ/util/ChampProperties.java53
-rw-r--r--champ-service/src/main/java/org/onap/champ/util/ChampServiceConstants.java14
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