Replaced all tabs with spaces in java and pom.xml
[so.git] / bpmn / mso-infrastructure-bpmn / src / main / java / org / onap / so / bpmn / common / workflow / service / WorkflowAsyncResource.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.so.bpmn.common.workflow.service;
24
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.UUID;
29 import javax.ws.rs.Consumes;
30 import javax.ws.rs.POST;
31 import javax.ws.rs.Path;
32 import javax.ws.rs.PathParam;
33 import javax.ws.rs.Produces;
34 import javax.ws.rs.core.Response;
35 import javax.ws.rs.ext.Provider;
36 import org.camunda.bpm.engine.ProcessEngineServices;
37 import org.camunda.bpm.engine.variable.impl.VariableMapImpl;
38 import org.onap.logging.ref.slf4j.ONAPLogConstants;
39 import org.onap.so.bpmn.common.workflow.context.WorkflowContext;
40 import org.onap.so.bpmn.common.workflow.context.WorkflowContextHolder;
41 import org.onap.so.bpmn.common.workflow.context.WorkflowResponse;
42 import org.openecomp.mso.bpmn.common.workflow.service.WorkflowProcessorException;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.slf4j.MDC;
46 import org.springframework.beans.factory.annotation.Autowired;
47 import org.springframework.stereotype.Component;
48 import io.swagger.annotations.Api;
49 import io.swagger.annotations.ApiOperation;
50
51
52 /**
53  * 
54  * @version 1.0 Asynchronous Workflow processing using JAX RS RESTeasy implementation Both Synchronous and Asynchronous
55  *          BPMN process can benefit from this implementation since the workflow gets executed in the background and the
56  *          server thread is freed up, server scales better to process more incoming requests
57  * 
58  *          Usage: For synchronous process, when you are ready to send the response invoke the callback to write the
59  *          response For asynchronous process - the activity may send a acknowledgement response and then proceed
60  *          further on executing the process
61  */
62 @Path("/async")
63 @Api(value = "/async", description = "Provides asynchronous starting of a bpmn process")
64 @Provider
65 @Component
66 public class WorkflowAsyncResource extends ProcessEngineAwareService {
67
68     private static final WorkflowContextHolder contextHolder = WorkflowContextHolder.getInstance();
69
70     long workflowPollInterval = 1000;
71
72     @Autowired
73     private WorkflowProcessor processor;
74
75     @Autowired
76     private WorkflowContextHolder workflowContext;
77
78     public void setProcessor(WorkflowProcessor processor) {
79         this.processor = processor;
80     }
81
82     protected static final Logger logger = LoggerFactory.getLogger(WorkflowAsyncResource.class);
83     protected static final long DEFAULT_WAIT_TIME = 60000; // default wait time
84
85     /**
86      * Asynchronous JAX-RS method that starts a process instance.
87      * 
88      * @param processKey the process key
89      * @param variableMap input variables to the process
90      * @return
91      */
92
93     @POST
94     @Path("/services/{processKey}")
95     @ApiOperation(value = "Starts a new process with the appropriate process Key",
96             notes = "Aysnc fall outs are only logged")
97     @Produces("application/json")
98     @Consumes("application/json")
99     public Response startProcessInstanceByKey(@PathParam("processKey") String processKey, VariableMapImpl variableMap) {
100         Map<String, Object> inputVariables = getInputVariables(variableMap);
101         try {
102             MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, getRequestId(inputVariables));
103             processor.startProcess(processKey, variableMap);
104             WorkflowResponse response = waitForResponse(getRequestId(inputVariables));
105             return Response.status(202).entity(response).build();
106         } catch (WorkflowProcessorException e) {
107             WorkflowResponse response = e.getWorkflowResponse();
108             return Response.status(500).entity(response).build();
109         } catch (Exception e) {
110             WorkflowResponse response = buildUnkownError(getRequestId(inputVariables), e.getMessage());
111             return Response.status(500).entity(response).build();
112         }
113     }
114
115     private WorkflowResponse waitForResponse(String requestId) throws Exception {
116         long currentWaitTime = 0;
117         while (DEFAULT_WAIT_TIME > currentWaitTime) {
118             Thread.sleep(workflowPollInterval);
119             currentWaitTime = currentWaitTime + workflowPollInterval;
120             WorkflowContext foundContext = contextHolder.getWorkflowContext(requestId);
121             if (foundContext != null) {
122                 contextHolder.remove(foundContext);
123                 return buildResponse(foundContext);
124             }
125         }
126         throw new Exception("TimeOutOccured");
127     }
128
129     private WorkflowResponse buildUnkownError(String requestId, String error) {
130         WorkflowResponse response = new WorkflowResponse();
131         response.setMessage(error);
132         response.setResponse("UnknownError, request id:" + requestId);
133         response.setMessageCode(500);
134         return response;
135     }
136
137     private WorkflowResponse buildResponse(WorkflowContext foundContext) {
138         return foundContext.getWorkflowResponse();
139     }
140
141     protected static String getOrCreate(Map<String, Object> inputVariables, String key) {
142         String value = Objects.toString(inputVariables.get(key), null);
143         if (value == null) {
144             value = UUID.randomUUID().toString();
145             inputVariables.put(key, value);
146         }
147         return value;
148     }
149
150     protected static String getRequestId(Map<String, Object> inputVariables) {
151         return getOrCreate(inputVariables, "mso-request-id");
152     }
153
154     protected boolean isProcessEnded(String processInstanceId) {
155         ProcessEngineServices pes = getProcessEngineServices();
156         return pes.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId)
157                 .singleResult() == null;
158     }
159
160     protected static Map<String, Object> getInputVariables(VariableMapImpl variableMap) {
161         Map<String, Object> inputVariables = new HashMap<>();
162         @SuppressWarnings("unchecked")
163         Map<String, Object> vMap = (Map<String, Object>) variableMap.get("variables");
164         for (Map.Entry<String, Object> entry : vMap.entrySet()) {
165             String vName = entry.getKey();
166             Object value = entry.getValue();
167             @SuppressWarnings("unchecked")
168             Map<String, Object> valueMap = (Map<String, Object>) value; // value, type
169             inputVariables.put(vName, valueMap.get("value"));
170         }
171         return inputVariables;
172     }
173
174 }