From 382e07e97ccd5f7bd47bdd735143ab3658661a68 Mon Sep 17 00:00:00 2001 From: Gurjeet Bedi Date: Wed, 6 Dec 2017 15:16:34 -0500 Subject: [PATCH] Port async pipeline for gizmo Port async pipeline for gizmo Issue-ID: AAI-552 Change-Id: I255127174d1154849f440bab8b1f0bda3311ec9f Signed-off-by: Gurjeet Bedi --- .../crud-api_v1/crud-api/v1/routes/crud2.route | 4 + src/main/java/org/onap/crud/event/GraphEvent.java | 2 +- .../org/onap/crud/logging/CrudServiceMsgs.java | 48 ++ .../crud/service/CrudAsyncGraphDataService.java | 469 ++++++++++++++ .../crud/service/CrudAsyncGraphEventCache.java | 79 +++ .../crud/service/CrudAsyncResponseConsumer.java | 116 ++++ .../onap/crud/service/CrudAsyncRestService.java | 693 +++++++++++++++++++++ .../onap/crud/service/CrudGraphDataService.java | 15 +- .../org/onap/crud/service/CrudThreadFactory.java | 46 ++ .../org/onap/crud/util/CrudServiceConstants.java | 2 + .../java/org/onap/crud/util/CrudServiceUtil.java | 11 + .../resources/logging/CrudServiceMsgs.properties | 21 + 12 files changed, 1493 insertions(+), 13 deletions(-) create mode 100644 src/main/ajsc/crud-api_v1/crud-api/v1/routes/crud2.route create mode 100644 src/main/java/org/onap/crud/service/CrudAsyncGraphDataService.java create mode 100644 src/main/java/org/onap/crud/service/CrudAsyncGraphEventCache.java create mode 100644 src/main/java/org/onap/crud/service/CrudAsyncResponseConsumer.java create mode 100644 src/main/java/org/onap/crud/service/CrudAsyncRestService.java create mode 100644 src/main/java/org/onap/crud/service/CrudThreadFactory.java diff --git a/src/main/ajsc/crud-api_v1/crud-api/v1/routes/crud2.route b/src/main/ajsc/crud-api_v1/crud-api/v1/routes/crud2.route new file mode 100644 index 0000000..40a98bf --- /dev/null +++ b/src/main/ajsc/crud-api_v1/crud-api/v1/routes/crud2.route @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/java/org/onap/crud/event/GraphEvent.java b/src/main/java/org/onap/crud/event/GraphEvent.java index 9e9c44c..b841389 100644 --- a/src/main/java/org/onap/crud/event/GraphEvent.java +++ b/src/main/java/org/onap/crud/event/GraphEvent.java @@ -157,7 +157,7 @@ public class GraphEvent { return gson.fromJson(json, GraphEvent.class); } catch (Exception ex) { - throw new CrudException("Unable to parse JSON string: ", Status.BAD_REQUEST); + throw new CrudException("Unable to parse JSON string: "+json, Status.BAD_REQUEST); } } diff --git a/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java b/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java index 6b04a0f..5c0da9c 100644 --- a/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java +++ b/src/main/java/org/onap/crud/logging/CrudServiceMsgs.java @@ -72,6 +72,54 @@ public enum CrudServiceMsgs implements LogMessageEnum { */ INSTANTIATE_AUTH_ERR, + /** + * Any info log related to ASYNC_DATA_SERVICE_INFO + * + *

Arguments: + * {0} - Info. + */ + ASYNC_DATA_SERVICE_INFO, + + /** + * Any error log related to ASYNC_DATA_SERVICE_ERROR + * + *

Arguments: + * {0} - Error. + */ + ASYNC_DATA_SERVICE_ERROR, + + /** + * Any info log related to ASYNC_DATA_CACHE_INFO + * + *

Arguments: + * {0} - Info. + */ + ASYNC_DATA_CACHE_INFO, + + /** + * Any error log related to ASYNC_DATA_CACHE_ERROR + * + *

Arguments: + * {0} - Error. + */ + ASYNC_DATA_CACHE_ERROR, + + /** + * Any info log related to ASYNC_RESPONSE_CONSUMER_INFO + * + *

Arguments: + * {0} - Info. + */ + ASYNC_RESPONSE_CONSUMER_INFO, + + /** + * Any error log related to ASYNC_RESPONSE_CONSUMER_ERROR + * + *

Arguments: + * {0} - Error. + */ + ASYNC_RESPONSE_CONSUMER_ERROR, + /** * Arguments: {0} Opertaion {1} URI {2} = Exception */ diff --git a/src/main/java/org/onap/crud/service/CrudAsyncGraphDataService.java b/src/main/java/org/onap/crud/service/CrudAsyncGraphDataService.java new file mode 100644 index 0000000..9efc7df --- /dev/null +++ b/src/main/java/org/onap/crud/service/CrudAsyncGraphDataService.java @@ -0,0 +1,469 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.crud.service; + +import com.att.ecomp.event.api.EventConsumer; +import com.att.ecomp.event.api.EventPublisher; + +import org.onap.aai.cl.api.LogFields; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.cl.mdc.MdcOverride; +import org.onap.crud.dao.GraphDao; +import org.onap.crud.entity.Edge; +import org.onap.crud.entity.Vertex; +import org.onap.crud.event.GraphEvent; +import org.onap.crud.event.GraphEvent.GraphEventOperation; +import org.onap.crud.event.GraphEvent.GraphEventResult; +import org.onap.crud.event.GraphEventEdge; +import org.onap.crud.event.GraphEventVertex; +import org.onap.crud.exception.CrudException; +import org.onap.crud.logging.CrudServiceMsgs; +import org.onap.crud.parser.CrudResponseBuilder; +import org.onap.crud.util.CrudProperties; +import org.onap.crud.util.CrudServiceConstants; +import org.onap.crud.util.CrudServiceUtil; +import org.onap.schema.OxmModelValidator; +import org.onap.schema.RelationshipSchemaValidator; + +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.annotation.PreDestroy; +import javax.ws.rs.core.Response.Status; + +public class CrudAsyncGraphDataService { + + private static Integer requestTimeOut; + + private GraphDao dao; + + private EventPublisher asyncRequestPublisher; + + private Timer timer; + + public static final Integer DEFAULT_REQUEST_TIMEOUT = 30000; + private static final Integer DEFAULT_ASYNC_RESPONSE_PROCESS_POLL_INTERVAL = 1000; + + private static Logger logger = LoggerFactory.getInstance() + .getLogger(CrudAsyncGraphDataService.class.getName()); + private static Logger metricsLogger = LoggerFactory.getInstance() + .getMetricsLogger(CrudAsyncGraphDataService.class.getName()); + private static LogFields OK_FIELDS = new LogFields(); + + static { + OK_FIELDS.setField(Status.OK, Status.OK.toString()); + } + + public static Integer getRequestTimeOut() { + return requestTimeOut; + } + + public CrudAsyncGraphDataService(GraphDao dao, + EventPublisher asyncRequestPublisher, + EventConsumer asyncResponseConsumer) throws CrudException { + + requestTimeOut = DEFAULT_REQUEST_TIMEOUT; + try { + requestTimeOut + = Integer.parseInt(CrudProperties.get(CrudServiceConstants.CRD_ASYNC_REQUEST_TIMEOUT)); + } catch (NumberFormatException ex) { + // Leave it as the default + } + + Integer responsePollInterval = DEFAULT_ASYNC_RESPONSE_PROCESS_POLL_INTERVAL; + try { + responsePollInterval = Integer + .parseInt(CrudProperties + .get(CrudServiceConstants.CRD_ASYNC_RESPONSE_PROCESS_POLL_INTERVAL)); + } catch (Exception ex) { + logger.error(CrudServiceMsgs.ASYNC_DATA_SERVICE_ERROR, "Unable to parse " + + CrudServiceConstants.CRD_ASYNC_RESPONSE_PROCESS_POLL_INTERVAL + + " error: " + ex.getMessage()); + } + + this.dao = dao; + + // Start the Response Consumer timer + CrudAsyncResponseConsumer crudAsyncResponseConsumer + = new CrudAsyncResponseConsumer(asyncResponseConsumer); + timer = new Timer("crudAsyncResponseConsumer-1"); + timer.schedule(crudAsyncResponseConsumer, responsePollInterval, responsePollInterval); + + this.asyncRequestPublisher = asyncRequestPublisher; + + // load the schemas + CrudServiceUtil.loadModels(); + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "CrudAsyncGraphDataService initialized SUCCESSFULLY!"); + } + + public class CollectGraphResponse implements Callable { + private volatile GraphEvent graphEvent; + private volatile CountDownLatch latch = new CountDownLatch(1); + + @Override + public GraphEvent call() throws TimeoutException { + try { + // Wait until graphEvent is available + latch.await(CrudAsyncGraphDataService.getRequestTimeOut(), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + latch.countDown(); + if (this.graphEvent != null) { + return this.graphEvent; + } else { + throw new TimeoutException(); + } + } + return this.graphEvent; + } + + public void populateGraphEvent(GraphEvent event) { + this.graphEvent = event; + latch.countDown(); + } + } + + private GraphEvent sendAndWait(GraphEvent event) throws Exception { + + long startTimeInMs = System.currentTimeMillis(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + MdcOverride override = new MdcOverride(); + override.addAttribute(MdcContext.MDC_START_TIME, formatter.format(startTimeInMs)); + + // publish to request queue + asyncRequestPublisher.sendSync(event.toJson()); + + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event submitted of type: " + event.getObjectType() + " with key: " + event.getObjectKey() + + " , transaction-id: " + event.getTransactionId() + " , operation: " + + event.getOperation().toString()); + + ExecutorService executor = Executors + .newSingleThreadExecutor(new CrudThreadFactory("TX-" + event.getTransactionId())); + CollectGraphResponse collector = new CollectGraphResponse(); + CrudAsyncGraphEventCache.put(event.getTransactionId(), collector); + GraphEvent response; + Future future = executor.submit(collector); + try { + response = future.get(requestTimeOut, TimeUnit.MILLISECONDS); + + } catch (InterruptedException | ExecutionException | TimeoutException e) { + CrudAsyncGraphEventCache.invalidate(event.getTransactionId()); + logger.error(CrudServiceMsgs.ASYNC_DATA_SERVICE_ERROR, + "Request timed out for transactionId: " + event.getTransactionId()); + future.cancel(true); + throw new CrudException("Timed out , transactionId: " + event.getTransactionId() + + " , operation: " + event.getOperation().toString(), Status.INTERNAL_SERVER_ERROR); + } finally { + //Kill the thread as the work is completed + executor.shutdownNow(); + } + metricsLogger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, OK_FIELDS, override, + "Total elapsed time for operation: " + event.getOperation().toString() + + " , transactionId: " + event.getTransactionId() + " is " + + Long.toString(System.currentTimeMillis() - startTimeInMs) + " ms"); + return response; + } + + public String addVertex(String version, String type, VertexPayload payload) throws Exception { + // Validate the incoming payload + Vertex vertex = OxmModelValidator.validateIncomingUpsertPayload(null, version, + type, payload.getProperties()); + // Create graph request event + GraphEvent event = GraphEvent.builder(GraphEventOperation.CREATE) + .vertex(GraphEventVertex.fromVertex(vertex, version)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return CrudResponseBuilder.buildUpsertVertexResponse( + OxmModelValidator.validateOutgoingPayload(version, + response.getVertex().toVertex()), version); + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String addEdge(String version, String type, EdgePayload payload) throws Exception { + Edge edge = RelationshipSchemaValidator.validateIncomingAddPayload(version, type, payload); + // Create graph request event + GraphEvent event = GraphEvent.builder(GraphEventOperation.CREATE) + .edge(GraphEventEdge.fromEdge(edge, version)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return CrudResponseBuilder.buildUpsertEdgeResponse( + RelationshipSchemaValidator.validateOutgoingPayload(version, response.getEdge().toEdge()), + version); + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + } + + public String updateVertex(String version, String id, String type, VertexPayload payload) + throws Exception { + Vertex vertex = OxmModelValidator.validateIncomingUpsertPayload(id, version, + type, payload.getProperties()); + GraphEvent event = GraphEvent.builder(GraphEventOperation.UPDATE) + .vertex(GraphEventVertex.fromVertex(vertex, version)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return CrudResponseBuilder.buildUpsertVertexResponse( + OxmModelValidator.validateOutgoingPayload(version, response.getVertex().toVertex()), + version); + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String patchVertex(String version, String id, String type, VertexPayload payload) + throws Exception { + Vertex existingVertex + = dao.getVertex(id, OxmModelValidator.resolveCollectionType(version, type)); + Vertex patchedVertex = OxmModelValidator.validateIncomingPatchPayload(id, version, + type, payload.getProperties(), + existingVertex); + GraphEvent event = GraphEvent.builder(GraphEventOperation.UPDATE) + .vertex(GraphEventVertex.fromVertex(patchedVertex, version)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return CrudResponseBuilder.buildUpsertVertexResponse( + OxmModelValidator.validateOutgoingPayload(version, response.getVertex().toVertex()), + version); + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String deleteVertex(String version, String id, String type) throws Exception { + type = OxmModelValidator.resolveCollectionType(version, type); + GraphEvent event = GraphEvent.builder(GraphEventOperation.DELETE) + .vertex(new GraphEventVertex(id, version, type, null)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return ""; + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String deleteEdge(String version, String id, String type) throws Exception { + RelationshipSchemaValidator.validateType(version, type); + GraphEvent event = GraphEvent.builder(GraphEventOperation.DELETE) + .edge(new GraphEventEdge(id, version, type, null, null, null)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return ""; + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String updateEdge(String version, String id, String type, EdgePayload payload) + throws Exception { + Edge edge = dao.getEdge(id, type); + Edge validatedEdge = RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, + payload); + GraphEvent event = GraphEvent.builder(GraphEventOperation.UPDATE) + .edge(GraphEventEdge.fromEdge(validatedEdge, version)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return CrudResponseBuilder.buildUpsertEdgeResponse( + RelationshipSchemaValidator.validateOutgoingPayload(version, + response.getEdge().toEdge()), version); + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String patchEdge(String version, String id, String type, EdgePayload payload) + throws Exception { + Edge edge = dao.getEdge(id, type); + Edge patchedEdge = RelationshipSchemaValidator.validateIncomingPatchPayload(edge, version, + payload); + GraphEvent event = GraphEvent.builder(GraphEventOperation.UPDATE) + .edge(GraphEventEdge.fromEdge(patchedEdge, version)).build(); + + GraphEvent response = sendAndWait(event); + if (response.getResult().equals(GraphEventResult.SUCCESS)) { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult()); + return CrudResponseBuilder.buildUpsertEdgeResponse( + RelationshipSchemaValidator.validateOutgoingPayload(version, response.getEdge().toEdge()), + version); + } else { + logger.info(CrudServiceMsgs.ASYNC_DATA_SERVICE_INFO, + "Event response received: " + response.getObjectType() + " with key: " + + response.getObjectKey() + " , transaction-id: " + response.getTransactionId() + + " , operation: " + event.getOperation().toString() + " , result: " + + response.getResult() + " , error: " + response.getErrorMessage()); + throw new CrudException("Operation Failed with transaction-id: " + response.getTransactionId() + + " Error: " + response.getErrorMessage(), response.getHttpErrorStatus()); + } + + } + + public String getEdge(String version, String id, String type) throws CrudException { + RelationshipSchemaValidator.validateType(version, type); + Edge edge = dao.getEdge(id, type); + + return CrudResponseBuilder.buildGetEdgeResponse(RelationshipSchemaValidator + .validateOutgoingPayload(version, edge), + version); + } + + public String getEdges(String version, String type, Map filter) + throws CrudException { + RelationshipSchemaValidator.validateType(version, type); + List items = dao.getEdges(type, + RelationshipSchemaValidator.resolveCollectionfilter(version, type, filter)); + return CrudResponseBuilder.buildGetEdgesResponse(items, version); + } + + public String getVertex(String version, String id, String type) throws CrudException { + type = OxmModelValidator.resolveCollectionType(version, type); + Vertex vertex = dao.getVertex(id, type); + List edges = dao.getVertexEdges(id); + return CrudResponseBuilder.buildGetVertexResponse(OxmModelValidator + .validateOutgoingPayload(version, vertex), edges, + version); + } + + public String getVertices(String version, String type, Map filter) + throws CrudException { + type = OxmModelValidator.resolveCollectionType(version, type); + List items = dao.getVertices(type, + OxmModelValidator.resolveCollectionfilter(version, type, filter)); + return CrudResponseBuilder.buildGetVerticesResponse(items, version); + } + + @PreDestroy + protected void preShutdown() { + timer.cancel(); + + } + + +} \ No newline at end of file diff --git a/src/main/java/org/onap/crud/service/CrudAsyncGraphEventCache.java b/src/main/java/org/onap/crud/service/CrudAsyncGraphEventCache.java new file mode 100644 index 0000000..c1ed5ff --- /dev/null +++ b/src/main/java/org/onap/crud/service/CrudAsyncGraphEventCache.java @@ -0,0 +1,79 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.crud.service; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import java.util.concurrent.TimeUnit; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.crud.logging.CrudServiceMsgs; +import org.onap.crud.service.CrudAsyncGraphDataService.CollectGraphResponse; +import org.onap.crud.util.CrudProperties; +import org.onap.crud.util.CrudServiceConstants; + +/** + * Self expiring Cache to hold request transactionIds . Events are expired + * automatically after 2 seconds of request time out + */ +public class CrudAsyncGraphEventCache { + private static Logger logger = LoggerFactory.getInstance().getLogger(CrudAsyncGraphEventCache + .class.getName()); + + private static Integer interval; + + static { + // Set the cache eviction timeout = request timeout + 2 sec for the + // buffer + interval = CrudAsyncGraphDataService.DEFAULT_REQUEST_TIMEOUT + 2000; + try { + interval = Integer + .parseInt(CrudProperties.get(CrudServiceConstants.CRD_ASYNC_REQUEST_TIMEOUT) + 2000); + } catch (Exception ex) { + logger.error(CrudServiceMsgs.ASYNC_DATA_CACHE_ERROR, "Unable to parse " + + CrudServiceConstants.CRD_ASYNC_REQUEST_TIMEOUT + " error: " + + ex.getMessage()); + } + } + + private final static Cache cache = CacheBuilder.newBuilder() + .expireAfterWrite(interval, TimeUnit.MILLISECONDS).build(); + + + public static void put(String uuid, CollectGraphResponse collector) { + cache.put(uuid, collector); + + } + + public static CollectGraphResponse get(String uuid) { + return cache.getIfPresent(uuid); + } + + public static void invalidate(String uuid) { + cache.invalidate(uuid); + } + +} \ No newline at end of file diff --git a/src/main/java/org/onap/crud/service/CrudAsyncResponseConsumer.java b/src/main/java/org/onap/crud/service/CrudAsyncResponseConsumer.java new file mode 100644 index 0000000..da7e6e5 --- /dev/null +++ b/src/main/java/org/onap/crud/service/CrudAsyncResponseConsumer.java @@ -0,0 +1,116 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.crud.service; + +import java.util.TimerTask; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.crud.event.GraphEvent; +import org.onap.crud.logging.CrudServiceMsgs; + +import com.att.ecomp.event.api.EventConsumer; + +public class CrudAsyncResponseConsumer extends TimerTask { + + private static Logger logger = LoggerFactory.getInstance().getLogger(CrudAsyncResponseConsumer + .class.getName()); + + private static Logger auditLogger = LoggerFactory.getInstance() + .getAuditLogger(CrudAsyncResponseConsumer.class.getName()); + + private EventConsumer asyncResponseConsumer; + + + public CrudAsyncResponseConsumer(EventConsumer asyncResponseConsumer) { + this.asyncResponseConsumer = asyncResponseConsumer; + logger.info(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_INFO, + "CrudAsyncResponseConsumer initialized SUCCESSFULLY! with event consumer " + + asyncResponseConsumer.getClass().getName()); + } + + + @Override + public void run() { + + logger.info(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_INFO, "Listening for graph events"); + + if (asyncResponseConsumer == null) { + logger.error(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_ERROR, + "Unable to initialize CrudAsyncRequestProcessor"); + } + + Iterable events = null; + try { + events = asyncResponseConsumer.consume(); + } catch (Exception e) { + logger.error(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_ERROR, e.getMessage()); + return; + } + + if (events == null || !events.iterator().hasNext()) { + logger.info(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_INFO, "No events recieved"); + + } + + for (String event : events) { + try { + + GraphEvent graphEvent = GraphEvent.fromJson(event); + auditLogger.info(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_INFO, + "Event received of type: " + graphEvent.getObjectType() + " with key: " + + graphEvent.getObjectKey() + " , transaction-id: " + + graphEvent.getTransactionId() + " , operation: " + + graphEvent.getOperation().toString()); + logger.info(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_INFO, + "Event received of type: " + graphEvent.getObjectType() + " with key: " + + graphEvent.getObjectKey() + " , transaction-id: " + + graphEvent.getTransactionId() + " , operation: " + + graphEvent.getOperation().toString()); + logger.debug(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_INFO, + "Event received with payload:" + event); + + if (CrudAsyncGraphEventCache.get(graphEvent.getTransactionId()) != null) { + CrudAsyncGraphEventCache.get(graphEvent.getTransactionId()) + .populateGraphEvent(graphEvent); + } else { + logger.error(CrudServiceMsgs.ASYNC_DATA_SERVICE_ERROR, + "Request timed out. Not sending response for transaction-id: " + + graphEvent.getTransactionId()); + } + + } catch (Exception e) { + logger.error(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_ERROR, e.getMessage()); + } + } + + try { + asyncResponseConsumer.commitOffsets(); + } catch (Exception e) { + logger.error(CrudServiceMsgs.ASYNC_RESPONSE_CONSUMER_ERROR, e.getMessage()); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/org/onap/crud/service/CrudAsyncRestService.java b/src/main/java/org/onap/crud/service/CrudAsyncRestService.java new file mode 100644 index 0000000..4769c93 --- /dev/null +++ b/src/main/java/org/onap/crud/service/CrudAsyncRestService.java @@ -0,0 +1,693 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.crud.service; + +import org.apache.cxf.jaxrs.ext.PATCH; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aaiauth.auth.Auth; +import org.onap.crud.exception.CrudException; +import org.onap.crud.logging.CrudServiceMsgs; +import org.onap.crud.logging.LoggingUtil; +import org.onap.crud.util.CrudServiceConstants; +import org.slf4j.MDC; + +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.Encoded; +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.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; + + +public class CrudAsyncRestService { + + private CrudAsyncGraphDataService crudAsyncGraphDataService; + Logger logger = LoggerFactory.getInstance().getLogger(CrudAsyncRestService.class.getName()); + Logger auditLogger = LoggerFactory.getInstance() + .getAuditLogger(CrudAsyncRestService.class.getName()); + private Auth auth; + + private String mediaType = MediaType.APPLICATION_JSON; + public static final String HTTP_PATCH_METHOD_OVERRIDE = "X-HTTP-Method-Override"; + + public CrudAsyncRestService(CrudAsyncGraphDataService crudAsyncGraphDataService) + throws Exception { + this.crudAsyncGraphDataService = crudAsyncGraphDataService; + this.auth = new Auth(CrudServiceConstants.CRD_AUTH_FILE); + } + + public enum Action { + POST, GET, PUT, DELETE, PATCH + } + + public void startup() { + + } + + @GET + @Path("/{version}/{type}/{id}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response getVertex(String content, @PathParam("version") String version, + @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded String uri, + @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.GET, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + try { + String result = crudAsyncGraphDataService.getVertex(version, id, type); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @GET + @Path("/{version}/{type}/") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response getVertices(String content, @PathParam("version") String version, + @PathParam("type") String type, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + Map filter = new HashMap(); + for (Map.Entry> e : uriInfo.getQueryParameters().entrySet()) { + filter.put(e.getKey(), e.getValue().get(0)); + } + + try { + String result = crudAsyncGraphDataService.getVertices(version, type, filter); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @GET + @Path("/relationships/{version}/{type}/{id}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response getEdge(String content, @PathParam("version") String version, + @PathParam("type") String type, + @PathParam("id") String id, @PathParam("uri") @Encoded String uri, + @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + try { + + String result = crudAsyncGraphDataService.getEdge(version, id, type); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @GET + @Path("/relationships/{version}/{type}/") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response getEdges(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("uri") @Encoded String uri, + @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.GET, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + Map filter = new HashMap(); + for (Map.Entry> e : uriInfo.getQueryParameters().entrySet()) { + filter.put(e.getKey(), e.getValue().get(0)); + } + + try { + String result = crudAsyncGraphDataService.getEdges(version, type, filter); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @PUT + @Path("/relationships/{version}/{type}/{id}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response updateEdge(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("id") String id, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + try { + EdgePayload payload = EdgePayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null && !payload.getId().equals(id)) { + throw new CrudException("ID Mismatch", Status.BAD_REQUEST); + } + String result; + + if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null + && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) + .equalsIgnoreCase("PATCH")) { + result = crudAsyncGraphDataService.patchEdge(version, id, type, payload); + } else { + + result = crudAsyncGraphDataService.updateEdge(version, id, type, payload); + } + + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @PATCH + @Path("/relationships/{version}/{type}/{id}") + @Consumes({"application/merge-patch+json"}) + @Produces({MediaType.APPLICATION_JSON}) + public Response patchEdge(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("id") String id, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + if (validateRequest(req, uri, content, Action.PATCH, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + try { + EdgePayload payload = EdgePayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null && !payload.getId().equals(id)) { + throw new CrudException("ID Mismatch", Status.BAD_REQUEST); + } + + String result = crudAsyncGraphDataService.patchEdge(version, id, type, payload); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @PUT + @Path("/{version}/{type}/{id}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response updateVertex(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("id") String id, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.PUT, CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + try { + VertexPayload payload = VertexPayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null && !payload.getId().equals(id)) { + throw new CrudException("ID Mismatch", Status.BAD_REQUEST); + } + String result; + if (headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) != null + && headers.getRequestHeaders().getFirst(HTTP_PATCH_METHOD_OVERRIDE) + .equalsIgnoreCase("PATCH")) { + result = crudAsyncGraphDataService.patchVertex(version, id, type, payload); + } else { + + result = crudAsyncGraphDataService.updateVertex(version, id, type, payload); + } + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @PATCH + @Path("/{version}/{type}/{id}") + @Consumes({"application/merge-patch+json"}) + @Produces({MediaType.APPLICATION_JSON}) + public Response patchVertex(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("id") String id, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.PATCH, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + try { + VertexPayload payload = VertexPayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null && !payload.getId().equals(id)) { + throw new CrudException("ID Mismatch", Status.BAD_REQUEST); + } + + String result = crudAsyncGraphDataService.patchVertex(version, id, type, payload); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @POST + @Path("/{version}/{type}/") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response addVertex(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("uri") @Encoded String uri, + @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.POST, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + try { + VertexPayload payload = VertexPayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null) { + throw new CrudException("ID specified , use Http PUT to update Vertex", + Status.BAD_REQUEST); + } + + if (payload.getType() != null && !payload.getType().equals(type)) { + throw new CrudException("Vertex Type mismatch", Status.BAD_REQUEST); + } + + String result = crudAsyncGraphDataService.addVertex(version, type, payload); + response = Response.status(Status.CREATED).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @POST + @Path("/{version}/") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response addVertex(String content, @PathParam("version") String version, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.POST, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + try { + + VertexPayload payload = VertexPayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null) { + throw new CrudException("ID specified , use Http PUT to update Vertex", + Status.BAD_REQUEST); + } + + if (payload.getType() == null || payload.getType().isEmpty()) { + throw new CrudException("Missing Vertex Type ", Status.BAD_REQUEST); + } + String result = crudAsyncGraphDataService.addVertex(version, payload.getType(), payload); + response = Response.status(Status.CREATED).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content).type(MediaType.APPLICATION_JSON) + .build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @POST + @Path("/relationships/{version}/{type}/") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response addEdge(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("uri") @Encoded String uri, + @Context HttpHeaders headers, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.POST, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + + try { + EdgePayload payload = EdgePayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null) { + throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST); + } + + if (payload.getType() != null && !payload.getType().equals(type)) { + throw new CrudException("Edge Type mismatch", Status.BAD_REQUEST); + } + String result = crudAsyncGraphDataService.addEdge(version, type, payload); + response = Response.status(Status.CREATED).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content) + .type(MediaType.APPLICATION_JSON).build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @POST + @Path("/relationships/{version}/") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response addEdge(String content, @PathParam("version") String version, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.POST, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + + try { + EdgePayload payload = EdgePayload.fromJson(content); + if (payload.getProperties() == null || payload.getProperties().isJsonNull()) { + throw new CrudException("Invalid request Payload", Status.BAD_REQUEST); + } + if (payload.getId() != null) { + throw new CrudException("ID specified , use Http PUT to update Edge", Status.BAD_REQUEST); + } + + if (payload.getType() == null || payload.getType().isEmpty()) { + throw new CrudException("Missing Edge Type ", Status.BAD_REQUEST); + } + String result = crudAsyncGraphDataService.addEdge(version, payload.getType(), payload); + + response = Response.status(Status.CREATED).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content) + .type(MediaType.APPLICATION_JSON).build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @DELETE + @Path("/{version}/{type}/{id}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response deleteVertex(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("id") String id, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + + if (validateRequest(req, uri, content, Action.DELETE, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + + try { + String result = crudAsyncGraphDataService.deleteVertex(version, id, type); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content) + .type(MediaType.APPLICATION_JSON).build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + @DELETE + @Path("/relationships/{version}/{type}/{id}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response deleteEdge(String content, @PathParam("version") String version, + @PathParam("type") String type, @PathParam("id") String id, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, + @Context UriInfo uriInfo, @Context HttpServletRequest req) { + + LoggingUtil.initMdcContext(req, headers); + + logger.debug("Incoming request..." + content); + Response response = null; + if (validateRequest(req, uri, content, Action.DELETE, + CrudServiceConstants.CRD_AUTH_POLICY_NAME)) { + + + try { + String result = crudAsyncGraphDataService.deleteEdge(version, id, type); + response = Response.status(Status.OK).entity(result).type(mediaType).build(); + } catch (CrudException ce) { + response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build(); + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } else { + response = Response.status(Status.FORBIDDEN).entity(content) + .type(MediaType.APPLICATION_JSON).build(); + } + + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + return response; + } + + protected boolean validateRequest(HttpServletRequest req, String uri, String content, + Action action, String authPolicyFunctionName) { + try { + String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite"); + String authUser = null; + if (cipherSuite != null) { + X509Certificate[] certChain = (X509Certificate[]) req + .getAttribute("javax.servlet.request.X509Certificate"); + X509Certificate clientCert = certChain[0]; + X500Principal subjectDn = clientCert.getSubjectX500Principal(); + authUser = subjectDn.toString(); + } + return this.auth.validateRequest(authUser.toLowerCase(), action.toString() + + ":" + authPolicyFunctionName); + } catch (Exception e) { + logResult(action, uri, e); + return false; + } + } + + void logResult(Action op, String uri, Exception e) { + + logger.error(CrudServiceMsgs.EXCEPTION_DURING_METHOD_CALL, op.toString(), + uri, e.getStackTrace().toString()); + + // Clear the MDC context so that no other transaction inadvertently + // uses our transaction id. + MDC.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/crud/service/CrudGraphDataService.java b/src/main/java/org/onap/crud/service/CrudGraphDataService.java index d7def67..4e42d44 100644 --- a/src/main/java/org/onap/crud/service/CrudGraphDataService.java +++ b/src/main/java/org/onap/crud/service/CrudGraphDataService.java @@ -30,15 +30,14 @@ import java.util.Map; import javax.ws.rs.core.Response.Status; -import org.onap.aaiutils.oxm.OxmModelLoader; import org.onap.crud.dao.GraphDao; import org.onap.crud.entity.Edge; import org.onap.crud.entity.Vertex; import org.onap.crud.exception.CrudException; import org.onap.crud.parser.CrudResponseBuilder; +import org.onap.crud.util.CrudServiceUtil; import org.onap.schema.OxmModelValidator; -import org.onap.schema.RelationshipSchemaLoader; import org.onap.schema.RelationshipSchemaValidator; import com.google.gson.JsonElement; @@ -50,18 +49,10 @@ public class CrudGraphDataService { public CrudGraphDataService(GraphDao dao) throws CrudException { this.dao = dao; - loadModels(); + CrudServiceUtil.loadModels(); } - private void loadModels() throws CrudException { - // load the schemas - try { - OxmModelLoader.loadModels(); - } catch (Exception e) { - throw new CrudException(e); - } - RelationshipSchemaLoader.loadModels(); - } + public String addVertex(String version, String type, VertexPayload payload) throws CrudException { Vertex vertex = OxmModelValidator.validateIncomingUpsertPayload(null, version, type, payload.getProperties()); diff --git a/src/main/java/org/onap/crud/service/CrudThreadFactory.java b/src/main/java/org/onap/crud/service/CrudThreadFactory.java new file mode 100644 index 0000000..be4f984 --- /dev/null +++ b/src/main/java/org/onap/crud/service/CrudThreadFactory.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.crud.service; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Thread factory for workers. + */ +public class CrudThreadFactory implements ThreadFactory { + + private AtomicInteger threadNumber = new AtomicInteger(1); + + private String threadPrefix; + + + public CrudThreadFactory(String threadPrefix) { + this.threadPrefix = threadPrefix; + } + + public Thread newThread(Runnable runnable) { + return new Thread(runnable, threadPrefix + "-" + threadNumber.getAndIncrement()); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/crud/util/CrudServiceConstants.java b/src/main/java/org/onap/crud/util/CrudServiceConstants.java index d3adaaa..70db5e3 100644 --- a/src/main/java/org/onap/crud/util/CrudServiceConstants.java +++ b/src/main/java/org/onap/crud/util/CrudServiceConstants.java @@ -36,4 +36,6 @@ public class CrudServiceConstants { public static final String CRD_AUTH_FILE = CRD_HOME_AUTH + "crud_policy.json"; public static final String CRD_CHAMP_AUTH_FILE = CRD_HOME_AUTH + "champ-cert.p12"; public static final String CRD_AUTH_POLICY_NAME = "crud"; + public static final String CRD_ASYNC_REQUEST_TIMEOUT = "crud.async.request.timeout"; + public static final String CRD_ASYNC_RESPONSE_PROCESS_POLL_INTERVAL = "crud.async.response.process.poll.interval"; } diff --git a/src/main/java/org/onap/crud/util/CrudServiceUtil.java b/src/main/java/org/onap/crud/util/CrudServiceUtil.java index 49b0317..88df8d1 100644 --- a/src/main/java/org/onap/crud/util/CrudServiceUtil.java +++ b/src/main/java/org/onap/crud/util/CrudServiceUtil.java @@ -23,7 +23,9 @@ */ package org.onap.crud.util; +import org.onap.aaiutils.oxm.OxmModelLoader; import org.onap.crud.exception.CrudException; +import org.onap.schema.RelationshipSchemaLoader; import javax.ws.rs.core.Response.Status; @@ -60,4 +62,13 @@ public class CrudServiceUtil { } } + public static void loadModels() throws CrudException { + // load the schemas + try { + OxmModelLoader.loadModels(); + } catch (Exception e) { + throw new CrudException(e); + } + RelationshipSchemaLoader.loadModels(); + } } diff --git a/src/main/resources/logging/CrudServiceMsgs.properties b/src/main/resources/logging/CrudServiceMsgs.properties index a4c2991..165b892 100644 --- a/src/main/resources/logging/CrudServiceMsgs.properties +++ b/src/main/resources/logging/CrudServiceMsgs.properties @@ -58,3 +58,24 @@ OXM_LOAD_ERROR=\ TRANSACTION=\ CRD0008I|\ TRANSACTION: {0} + +ASYNC_DATA_SERVICE_INFO=\ + CRD0509I|\ + AsyncDataService: {0} +ASYNC_DATA_SERVICE_ERROR=\ + CRD0510E|\ + AsyncDataService Error: {0} + +ASYNC_DATA_CACHE_INFO=\ + CRD0511I|\ + AsyncDataCache: {0} +ASYNC_DATA_CACHE_ERROR=\ + CRD0512E|\ + AsyncDataCache Error: {0} + +ASYNC_RESPONSE_CONSUMER_INFO=\ + CRD0513I|\ + AsyncResponseConsumer: {0} +ASYNC_RESPONSE_CONSUMER_ERROR=\ + CRD0514E|\ + AsyncResponseConsumer Error: {0} \ No newline at end of file -- 2.16.6