Service activator
Camunda

Service activator
Camunda


Download Service_activator.bpmn file Service_activator_C8.zip file ⤳ case study requires Spring Boot Java

Download Service_activator_C8_V2.zip file ⤳ case study requires Spring Boot Java

Requirements

Service activator design pattern offers a single entry point for a business service while hiding the way “concrete” services may be requested to provide the expected business data. Indeed, possible failures resulting from requests must lead to appropriate tactics to serve the required data

As an illustration, case study is the search for the up-to-date currency exchange rate (timestamp of rate capture as well) between the Moroccan Dirham against the US Dollar and/or the Euro. This occurs through the call of two professional RESTful APIs with free subscription

Service activator pattern

Process variable

REST outbound connector

Data

REST outbound connectorOutput mapping

Admin. console

Admin. console ⤳ Process variable

REST outbound connectorError handling

BPMN error event*

* openexchangerates_org_defect as value of Code field for BPMN error event creates the mapping (see prior slide)

More on BPMN
error event

Try it yourself (Camunda 8 Run is already started)

  1. Load Service_activator.bpmn file within Camunda Modeler
  2. Unzip Service_activator_C8.zip file and run Service_activator_C8 Java project in your favorite IDE
  3. Deploy Service_activator.bpmn and next create process instance within Camunda Modeler ⤳ check result in http://localhost:8080/operate console
  4. To create an error, change 678cd96edd4b4f3eb637bf74ef8e0815 to 678cd96edd4b4f3eb637bf74ef8e0816 within openexchangerates.org task
  5. Re-deploy Service_activator.bpmn and next re-create process instance within Camunda Modeler ⤳ check result in http://localhost:8080/operate console

Execution listener* in model (as Job worker)

*Doc.

Execution listener in code (as Job worker)

package com.BarbierDarnal.service_activator;

@org.springframework.stereotype.Component
public class Openexchangerates_org_success_execution_listener {
    // 'type' attribute operates the mapping with the BPMN model:
    @io.camunda.client.annotation.JobWorker(type = "Openexchangerates_org_success")
    public void my_execution_listener(final io.camunda.client.api.response.ActivatedJob job) {
        Object when = job.getVariable("when"); // 'when' process variable...
        System.out.println("'when' within 'Openexchangerates_org_success': " + when.toString());
    }
}

Script task as Job worker (model)

Script task as Job worker (code)

@org.springframework.stereotype.Component
public class Service_activator_job_worker_example {
    private final static org.slf4j.Logger _Log = org.slf4j.LoggerFactory.getLogger(Service_activator_job_worker_example.class);
    @io.camunda.client.annotation.JobWorker(type = "Service_activator_job_worker_example")
    public void my_service_task(final io.camunda.client.api.worker.JobClient client, final io.camunda.client.api.response.ActivatedJob job, @io.camunda.client.annotation.Variable(name = "Comment_ca_va_") @jakarta.annotation.Nullable String plutot_bien) {
        _Log.info("Processing 'Service_activator_job_worker_example': {}", job.getKey());
        System.out.println("Comment ça va ? " + plutot_bien);
        Object one_US_dollar_to_Moroccan_dirham = job.getVariable("one_US_dollar_to_Moroccan_dirham");
        System.out.println("'one_US_dollar_to_Moroccan_dirham': " + one_US_dollar_to_Moroccan_dirham.toString());
        try {
            var timestamp = new java.sql.Timestamp(1000 * ((Number) job.getVariable("timestamp")).longValue());
            String when = timestamp.toLocalDateTime().format(java.time.format.DateTimeFormatter.ISO_DATE_TIME);
            System.out.println("'when' within 'Service_activator_job_worker_example': " + when);
            client.newCompleteCommand(job).variable("when", when).send().join(); // Creation of 'when' as process var.
        } catch (ClassCastException cce) {System.err.println("Push system error to BPMN? No...");}
        _Log.info("'Service_activator_job_worker_example' completed: {}", job.getKey());
    }
}

Connector secret and

Connector secret.env file of Camunda 8 Run

Service activator pattern (ver. 2 ⤳ Service_activator_C8_V2.zip)

Call activity (caller)

Call activity (callee) ⤳ model

Call activity (callee) ⤳ code

@org.springframework.stereotype.Component
public class Log_error implements io.camunda.client.api.worker.JobHandler {

    @io.camunda.client.annotation.JobWorker(type = "Log_error", autoComplete = false)
    @Override
    public void handle(final io.camunda.client.api.worker.JobClient client, final io.camunda.client.api.response.ActivatedJob job) {
        // All parent process variables have been passed:
        // job.getVariablesAsMap().forEach((variable_name, variable_value) -> System.out.println(variable_name + ": " + variable_value.toString()));
        Object error_message = job.getVariable("error_message"); // 'error_message' parent process variable...
        System.err.println(error_message.toString());
        client.newCompleteCommand(job).send();
    }
}

Event subprocess triggering (1/3)

Event subprocess triggering (2/3)

Event subprocess triggering (3/3)

Event subprocess triggering ⤳ passed data (1/2)

Event subprocess triggering ⤳ passed data (2/2)

Try it yourself (Camunda 8 Run is already started)

  1. Deploy Log_error.bpmn and Service_activator_V2.bpmn found within Service_activator_C8_V2.zip
  2. Create Service_activator_V2.bpmn process instance

© BarbierDarnal.com