t09 Workflow Connector
t09 Workflow Connector
Connector Pattern
Tries to solve:
Winter 2021
Considerations
1. Process Complexity
a. Best for large scale processes
2. Variety of choices
a. Flexible for different use cases
b. The best are very expensive
3. Ease of use
a. Hides complexity instead of reducing it
b. Testing can also be difficult
c. Process definition changes are much simpler to change than the
underlying code that depends on it
Winter 2021
Process Model
Winter 2021
Required Resources
Camunda:
Open source workflow engine and modeller.
Download link + instructions: https://camunda.com/download/
Modeler download link + instructions: https://camunda.com/download/modeler/
Winter 2021
Tasks
A Service Task is used to invoke services. In A User Task is used to model work that
Camunda this is done by calling Java code or needs to be done by a human actor. When
providing a work item for an external worker the process execution arrives at such a User
to complete asynchronously or invoking a Task, a new task is created in the task list of
logic which is implemented in form of the user(s) or group(s) assigned to that task.
webservices.
Winter 2021
Gateways
Parallel Gateway:
Winter 2021
/**
Part 1
*/
public static String readResponse(CloseableHttpResponse response)
throws IOException {
// Handling the IO Stream from the response using scanner
package FormApp; Scanner sc = new Scanner(response.getEntity().getContent());
StringBuilder stringResponse = new StringBuilder();
import org.apache.http.client.methods.CloseableHttpResponse; while (sc.hasNext()) {
import org.apache.http.client.methods.HttpGet; stringResponse.append(sc.nextLine());
import org.apache.http.client.methods.HttpPost; stringResponse.append("\n");
import org.apache.http.entity.StringEntity; }
import org.apache.http.impl.client.CloseableHttpClient; response.close();
import org.apache.http.impl.client.HttpClients; return stringResponse.toString();
import org.json.JSONArray; }
import org.json.JSONObject;
/**
import java.io.IOException; * Extract ID from JSON String
import java.util.Scanner; * @param json String
* @return ID of JSON Object
public class API { */
public static String getIdFromJSON(String json) {
/** JSONObject jsonObject = new JSONObject(json);
* Create university application process return jsonObject.getString("id");
* @return String of the process ID }
*/
public static String createUniApplicationProcess() { /**
// Create closeable http client to execute requests with * Method for creating the application (completing the create
try (CloseableHttpClient client = HttpClients.createDefault()) { application task)
// Creating the request to execute * @param processId ID for the process to create the application for
HttpPost httpPost = new HttpPost( * @param gpa Grade of the application
"http://localhost:8080/engine-rest/process- * @param essay Essay of the application
definition/key/UniversityApplication/submit-form"); */
httpPost.setHeader("Accept", "application/json"); public static void createApplication(String processId, double gpa,
httpPost.setHeader("Content-type", "application/json"); String essay) {
httpPost.setEntity(new StringEntity("{}")); String taskId = getTaskID(processId);
String body = createBodyForVariables(gpa, essay);
// Executing the request using the http client and obtaining the completeTask(taskId, body);
response }
CloseableHttpResponse response = client.execute(httpPost);
String jsonResponse = readResponse(response); /**
String applicationId = getIdFromJSON(jsonResponse); * Get task ID of the first task of a given process
System.out.printf("Your application ID is: %s\nPlease save it * @param processID of the process to check the first task with
somewhere.", applicationId); * @return id of the first task
return applicationId; */
} catch (IOException e) { public static String getTaskID(String processID) {
}
e.printStackTrace();
return "Failed to get customers"; Winter 2021
JSONArray jsonArray = getTaskList(processID);
JSONObject obj = (JSONObject) jsonArray.get(0);
return obj.getString("id");
} }
/**
* Complete tasks for a specified taskID
* @param taskId to complete
Part 2
try (CloseableHttpClient client = HttpClients.createDefault()) {
String URL = String.format("http://localhost:8080/engine-
rest/task/%s/complete", taskId);
// Creating the request to execute
HttpPost httpPost = new HttpPost(URL);
httpPost.setHeader("Accept", "application/json");
/** httpPost.setHeader("Content-type", "application/json");
* Getting the task list of a given process
* @param processID of the process httpPost.setEntity(new StringEntity(body));
* @return JSON Array of tasks
*/ // Executing the request using the http client and obtaining the
private static JSONArray getTaskList(String processID) { response
try (CloseableHttpClient client = HttpClients.createDefault()) { client.execute(httpPost);
String URL = String.format("http://localhost:8080/engine- } catch (IOException e) {
rest/task/?processInstanceId=%s", e.printStackTrace();
processID); }
HttpGet httpGet = new HttpGet(URL);
CloseableHttpResponse response = client.execute(httpGet); }
String jsonResponse = readResponse(response);
return new JSONArray(jsonResponse); /**
} catch (IOException e ) { * Check whether a process exists
return new JSONArray("[]"); * @param processID to use to check whether the process exists
} * @return whether it exists
} */
public static boolean processExists(String processID) {
/**
* Create the JSON body for the process variables to be posted when try (CloseableHttpClient client = HttpClients.createDefault()) {
completing the create application task String url = String.format("http://localhost:8080/engine-
* @param gpa process variable rest/process-instance/%s", processID);
* @param essay process variable HttpGet httpGet = new HttpGet(url);
* @return JSON String to be posted CloseableHttpResponse httpResponse = client.execute(httpGet);
*/ String jsonResponse = readResponse(httpResponse);
private static String createBodyForVariables(double gpa, String essay) { JSONObject obj = new JSONObject(jsonResponse);
JSONObject variables = new JSONObject(); boolean t = (obj.has("type") &&
JSONObject gpaJson = new JSONObject();
gpaJson.put("value", gpa); obj.getString("type").equals("InvalidRequestException"));
gpaJson.put("type", "double"); return !(obj.has("type") &&
variables.put("gpa", gpaJson); obj.getString("type").equals("InvalidRequestException"));
} catch (IOException e) {
JSONObject essayJson = new JSONObject(); return false;
essayJson.put("value", essay); }
essayJson.put("type", "string"); }
variables.put("essay", essayJson);
Winter 2021
JSONObject body = new JSONObject();
body.put("variables", variables);
return body.toString();
}
API For User Tasks - Part 3
/**
* Check whether the process is at the confirm acceptance task of
the process
* @param processID to check process
* @return whether the current task is confirm acceptance
*/
public static boolean canConfirmAcceptance(String processID) {
return validateInCurrentActivity(processID,
"ConfirmAcceptance");
}
/**
* Check whether the process is at the create application task of
the process
* @param processID to check process
* @return whether the current task is create application
*/
public static boolean canCreateApplication(String processID) {
return validateInCurrentActivity(processID,
"CreateApplication");
}
/**
* Validate if the first task in a task list of a process is the
specified activity
* @param processID of the process to look into
* @param activityID to validate the current activity
* @return whether the current activity is the one passed
*/
private static boolean validateInCurrentActivity(String processID,
String activityID) {
JSONArray taskList = getTaskList(processID);
if (taskList.length() != 1) {
return false;
} else {
JSONObject task = taskList.getJSONObject(0);
return
task.getString("taskDefinitionKey").equals(activityID);
}
}
Winter 2021
}
/**
* Console app portion for handling editing of the task of a process that was already
created
Part 1
String applicationId = input.nextLine();
if (!API.processExists(applicationId)) {
System.out.println("Your application does not exist in our system.\nPlease try
to create an application " +
"first.");
return;
}
package FormApp; if (!API.canCreateApplication(applicationId)) {
System.out.println("Your application is unable to be edited at the moment as
import java.util.Scanner; it may be in the process of " +
"being reviewed.\nIf your application has already been confirmed,
public class Console { please select the appropriate" +
public static void main(String[] args) { " choice when starting up this application.\n");
System.out.println("Welcome!"); return;
System.out.println("Pick your choice and press enter."); }
System.out.println("1 - Create University application"); createApplication(input, applicationId);
System.out.println("2 - Confirm Acceptance to University"); }
System.out.println("3 - Edit Application");
Scanner input = new Scanner(System.in); /**
String choice = input.nextLine(); * Console app portion for handling creation of the application/completing that task
* @param input scanner for taking user input
switch (choice) { * @param processID processID to complete the task for
case "1": */
handleApplication(input); private static void createApplication(Scanner input, String processID) {
break; System.out.println("Creating University Application.\n");
case "2": System.out.print("State your GPA: ");
handleConfirmation(input); double gpa = input.nextDouble();
break; input.nextLine();
case "3": System.out.printf("GPA: %.2f\n", gpa);
editApplication(input); System.out.println("Write a small essay about why you want to join this
break; university.\n" +
default: "Press Enter when you are finished.");
System.out.println("That isn't part of the available choices."); String essay = input.nextLine();
break; System.out.printf("Essay: %s\n", essay);
} API.createApplication(processID, gpa, essay);
input.close();
} System.out.printf("Your Application ID is: %s.\nPlease write it down and keep
it.", processID);
/** }
* Used to create the process and then trigger the console function for
creating/completing the create application
* task
* @param input scanner for taking user input
*/
private static void handleApplication(Scanner input) { Winter 2021
// Start Application Process and get the task ID for the first task.
String processID = API.createUniApplicationProcess();
createApplication(input, processID);
}
Console for User Task - Part 2
/**
* Console app portion for handling confirmation of university
acceptance
* @param input Scanner for taking user input
*/
private static void handleConfirmation(Scanner input) {
System.out.println("Please enter your Application ID.");
String applicationId = input.nextLine();
if (!API.processExists(applicationId)) {
System.out.println("Your application does not exist in our
system.\nPlease try to create an application " +
"first.");
return;
}
if (!API.canConfirmAcceptance(applicationId)) {
System.out.println("Unfortunately, you weren't accepted to
this University.\nYou may try to submit a new" +
" application.");
return;
}
Winter 2021
import java.util.logging.Logger;
import org.camunda.bpm.client.ExternalTaskClient;
Winter 2021
})
.open();
}
}
References
Camunda Rest API: https://docs.camunda.org/manual/latest/reference/rest/
Book: Service Design Patterns Fundamental Design Solutions for SOAP/WSDL and
RESTful Web Services
Winter 2021
Extra Resources
Gettings Started: https://www.youtube.com/watch?v=2XeTJQfz_YQ
Winter 2021