2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.mso.bpmn.gamma.workflow.service;
23 import java.util.concurrent.DelayQueue;
24 import java.util.concurrent.TimeUnit;
26 import javax.ws.rs.core.Response;
28 import org.jboss.resteasy.spi.AsynchronousResponse;
31 import org.openecomp.mso.logger.MessageEnum;
32 import org.openecomp.mso.logger.MsoLogger;
35 * Workflow Context Holder instance which can be accessed elsewhere either in groovy scripts or Java
39 public class WorkflowContextHolder {
41 private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
42 private static final String logMarker = "[WORKFLOW-CONTEXT-HOLDER]";
43 private static WorkflowContextHolder instance = null;
46 * Delay Queue which holds workflow context holder objects
48 private final DelayQueue<WorkflowContext> responseQueue = new DelayQueue<WorkflowContext>();
49 private final TimeoutThread timeoutThread = new TimeoutThread();
51 private WorkflowContextHolder() {
52 timeoutThread.start();
56 * Singleton holder which eliminates hot lock
57 * Since the JVM synchronizes static method there is no synchronization needed for this method
60 public static synchronized WorkflowContextHolder getInstance() {
61 if (instance == null) {
62 instance = new WorkflowContextHolder();
67 public void put(WorkflowContext context) {
68 msoLogger.debug(logMarker + " Adding context to the queue: "
69 + context.getRequestId());
70 responseQueue.put(context);
73 public void remove(WorkflowContext context) {
74 msoLogger.debug(logMarker + " Removing context from the queue: "
75 + context.getRequestId());
76 responseQueue.remove(context);
79 public WorkflowContext getWorkflowContext(String requestId) {
80 // Note: DelayQueue interator is threadsafe
81 for (WorkflowContext context : responseQueue) {
82 if (requestId.equals(context.getRequestId())) {
83 msoLogger.debug("Found context for request id: " + requestId);
88 msoLogger.debug("Unable to find context for request id: " + requestId);
93 * Builds the callback response object to respond to client
95 * @param processInstanceId
97 * @param callbackResponse
100 public Response processCallback(String processKey, String processInstanceId,
101 String requestId, WorkflowCallbackResponse callbackResponse) {
102 WorkflowResponse workflowResponse = new WorkflowResponse();
103 WorkflowContext workflowContext = getWorkflowContext(requestId);
105 if (workflowContext == null) {
106 msoLogger.debug("Unable to correlate workflow context for request id: " + requestId
107 + ":processInstance Id:" + processInstanceId
108 + ":process key:" + processKey);
109 workflowResponse.setMessage("Fail");
110 workflowResponse.setMessageCode(400);
111 workflowResponse.setResponse("Unable to correlate workflow context, bad request. Request Id: " + requestId);
112 return Response.serverError().entity(workflowResponse).build();
115 responseQueue.remove(workflowContext);
117 msoLogger.debug("Using callback response for request id: " + requestId);
118 workflowResponse.setResponse(callbackResponse.getResponse());
119 workflowResponse.setProcessInstanceID(processInstanceId);
120 workflowResponse.setMessageCode(callbackResponse.getStatusCode());
121 workflowResponse.setMessage(callbackResponse.getMessage());
122 sendWorkflowResponseToClient(processKey, workflowContext, workflowResponse);
123 return Response.ok().entity(workflowResponse).build();
127 * Send the response to client asynchronously when invoked by the BPMN process
129 * @param workflowContext
130 * @param workflowResponse
132 private void sendWorkflowResponseToClient(String processKey, WorkflowContext workflowContext,
133 WorkflowResponse workflowResponse) {
134 msoLogger.debug(logMarker + "Sending the response for request id: " + workflowContext.getRequestId());
135 recordEvents(processKey, workflowResponse, workflowContext.getStartTime());
136 Response response = Response.status(workflowResponse.getMessageCode()).entity(workflowResponse).build();
137 AsynchronousResponse asyncResp = workflowContext.getAsynchronousResponse();
138 asyncResp.setResponse(response);
142 * Timeout thread which monitors the delay queue for expired context and send timeout response
146 private class TimeoutThread extends Thread {
148 while (!isInterrupted()) {
150 WorkflowContext requestObject = responseQueue.take();
151 msoLogger.debug("Time remaining for request id: " + requestObject.getRequestId() + ":" + requestObject.getDelay(TimeUnit.MILLISECONDS));
152 msoLogger.debug("Preparing timeout response for " + requestObject.getProcessKey() + ":" + ":" + requestObject.getRequestId());
153 WorkflowResponse response = new WorkflowResponse();
154 response.setMessage("Fail");
155 response.setResponse("Request timedout, request id:" + requestObject.getRequestId());
156 //response.setProcessInstanceID(requestObject.getProcessInstance().getProcessInstanceId());
157 recordEvents(requestObject.getProcessKey(), response, requestObject.getStartTime());
158 response.setMessageCode(500);
159 Response result = Response.status(500).entity(response).build();
160 requestObject.getAsynchronousResponse().setResponse(result);
161 msoLogger.debug("Sending timeout response for request id:" + requestObject.getRequestId() + ":response:" + response);
162 } catch (InterruptedException e) {
164 } catch (Exception e) {
165 msoLogger.debug("WorkflowContextHolder timeout thread caught exception: " + e);
166 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(),
167 MsoLogger.ErrorCode.UnknownError, "Error in WorkflowContextHolder timeout thread");
172 msoLogger.debug("WorkflowContextHolder timeout thread interrupted, quitting");
176 private static void recordEvents(String processKey, WorkflowResponse response,
179 msoLogger.recordMetricEvent ( startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
180 logMarker + response.getMessage() + " for processKey: "
181 + processKey + " with response: " + response.getResponse(), "BPMN", MDC.get(processKey), null);
183 msoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, logMarker
184 + response.getMessage() + " for processKey: "
185 + processKey + " with response: " + response.getResponse());