Saltar a contenido

Bpmn Element Processors

Cada tipo de elemento BPMN tiene un procesador dedicado que implementa su semántica de ejecución. La arquitectura usa composición sobre herencia: los procesadores delegan comportamientos transversales (jobs, variables, eventos) a clases Behavior reutilizables. Un registry central (EnumMap) mapea cada BpmnElementType a su procesador concreto.

Interfaces base

BpmnElementProcessor\<T extends ExecutableFlowElement>

Interfaz principal que define el ciclo de vida de procesamiento de cualquier elemento BPMN. Cada método corresponde a una transición en la máquina de estados de ejecución.

Método Cuándo se invoca Responsabilidad típica
onActivate(T element, BpmnElementContext context) Al entrar en estado ACTIVATING Evaluar condiciones de entrada, preparar el elemento. Retorna void; el procesador decide si continúa o suspende.
finalizeActivation(T, BpmnElementContext) Transición ACTIVATING → ACTIVATED Aplicar input mappings, suscribirse a eventos, crear jobs. Es el "commit" de la activación.
onComplete(T, BpmnElementContext) Al entrar en estado COMPLETING Evaluar condiciones de salida, verificar que el trabajo está hecho.
finalizeCompletion(T, BpmnElementContext) Transición COMPLETING → COMPLETED Aplicar output mappings, propagar variables, tomar sequence flows salientes.
onTerminate(T, BpmnElementContext) Al entrar en estado TERMINATING Cancelar trabajos pendientes, desuscribirse de eventos.
finalizeTermination(T, BpmnElementContext) Transición TERMINATING → TERMINATED Limpiar estado, notificar al contenedor padre.

BpmnElementContainerProcessor\<T extends ExecutableFlowElement>

Extiende BpmnElementProcessor<T> para elementos que contienen otros elementos (sub-procesos, multi-instance). Agrega callbacks para gestionar el ciclo de vida de los hijos:

Método Propósito
onChildActivating(T, BpmnElementContext, BpmnElementContext childContext) Notificación de que un hijo está por activarse. Permite al padre validar o vetar.
onChildCompleting(T, BpmnElementContext, BpmnElementContext childContext) Un hijo está completándose. El padre puede inspeccionar resultados.
beforeExecutionPathCompleted(T, BpmnElementContext) Antes de que un camino de ejecución dentro del contenedor termine. Usado en parallel gateways y multi-instance.
afterExecutionPathCompleted(T, BpmnElementContext) Después de completar un camino. El contenedor decide si todos los caminos terminaron y puede completarse a sí mismo.
onChildTerminated(T, BpmnElementContext, BpmnElementContext childContext) Un hijo fue terminado (por cancelación, error boundary, etc.). El padre ajusta su estado interno.

Registro de procesadores (EnumMap)

La clase BpmnProcessors mantiene un EnumMap<BpmnElementType, BpmnElementProcessor<?>> que se inicializa al arrancar el engine. Cada tipo de elemento BPMN soportado tiene exactamente un procesador registrado:

# BpmnElementType Procesador Notas
1 PROCESS ProcessProcessor Raíz de toda instancia. Container processor.
2 START_EVENT StartEventProcessor None start, message start, timer start, signal start.
3 END_EVENT EndEventProcessor None end, message end, error end, escalation end, terminate end, compensation end, signal end.
4 INTERMEDIATE_CATCH_EVENT IntermediateCatchEventProcessor Message, timer, signal, link, conditional.
5 INTERMEDIATE_THROW_EVENT IntermediateThrowEventProcessor None, message, signal, escalation, compensation, link.
6 BOUNDARY_EVENT BoundaryEventProcessor Interrupting y non-interrupting. Timer, message, error, signal, escalation, conditional, compensation.
7 SEQUENCE_FLOW SequenceFlowProcessor Evalúa condiciones, activa el target. Maneja también la lógica de join en parallel gateways.
8 EXCLUSIVE_GATEWAY ExclusiveGatewayProcessor Split: evalúa condiciones. Join: passthrough (primer token).
9 PARALLEL_GATEWAY ParallelGatewayProcessor Solo fork; el join lo maneja el SequenceFlowProcessor contando incoming flows.
10 EVENT_BASED_GATEWAY EventBasedGatewayProcessor Activa todas las ramas de catch events; la primera que dispara cancela las demás.
11 INCLUSIVE_GATEWAY InclusiveGatewayProcessor Split: activa todas las ramas cuya condición es true (al menos una). Join: espera todos los caminos activos.
12 SERVICE_TASK ServiceTaskProcessor Crea job para job workers externos.
13 RECEIVE_TASK ReceiveTaskProcessor Se suscribe a un mensaje y espera correlación.
14 USER_TASK UserTaskProcessor Crea una tarea para usuarios humanos. Lifecycle especial con asignación/reclamación.
15 SEND_TASK SendTaskProcessor Crea job (igual que service task, semánticamente distinto).
16 SCRIPT_TASK ScriptTaskProcessor Crea job para ejecución de scripts. FEEL inline o job worker.
17 BUSINESS_RULE_TASK BusinessRuleTaskProcessor Dual mode: evaluación DMN directa o job worker.
18 MANUAL_TASK ManualTaskProcessor Pass-through: se activa y completa inmediatamente.
19 SUB_PROCESS SubProcessProcessor Embedded sub-process. Container processor con input/output mappings propios.
20 EVENT_SUB_PROCESS EventSubProcessProcessor Sub-proceso activado por evento (error, message, timer, signal, escalation, compensation).
21 MULTI_INSTANCE_BODY MultiInstanceBodyProcessor Wrapper que crea N instancias del inner activity. Sequential o parallel. Container processor.
22 CALL_ACTIVITY CallActivityProcessor Invoca otro proceso por processId. Propagación de variables configurable.
23 COMPENSATION_HANDLER CompensationHandlerProcessor Ejecuta la lógica de compensación asociada a una actividad completada.
24 AD_HOC_SUB_PROCESS AdHocSubProcessProcessor Sub-proceso ad-hoc donde las actividades pueden ejecutarse en cualquier orden.

Composición: clases Behavior

En vez de heredar comportamiento, los procesadores reciben instancias de behaviors inyectadas. Esto permite que un ServiceTaskProcessor y un SendTaskProcessor compartan exactamente la misma lógica de creación de jobs sin duplicar código.

BpmnJobBehavior

Gestiona la creación y lifecycle de jobs: - createNewJob(context, element): escribe un record JobIntent.CREATED con type, retries, timeout, custom headers. - cancelJob(context): cancela el job activo del elemento. - resolveJobIncident(context): resuelve un incidente asociado al job.

Usado por: ServiceTaskProcessor, SendTaskProcessor, ScriptTaskProcessor, BusinessRuleTaskProcessor, UserTaskProcessor.

BpmnIncidentBehavior

Crea y resuelve incidentes cuando un procesador encuentra un error no recuperable (condición inválida, mapping fallido, job sin retries): - createIncident(context, errorType, errorMessage): escribe un IncidentIntent.CREATED. - resolveIncidents(context): resuelve todos los incidentes abiertos del elemento.

BpmnVariableMappingBehavior

Aplica input y output mappings definidos en el modelo BPMN: - applyInputMappings(context, element): evalúa expresiones FEEL de los input mappings y crea variables en el scope local del elemento. - applyOutputMappings(context, element): evalúa output mappings y escribe variables en el scope padre.

Los mappings son expresiones FEEL evaluadas contra el scope de variables actual. Si un mapping falla (expresión inválida, tipo incompatible), se crea un incidente via BpmnIncidentBehavior.

BpmnEventSubscriptionBehavior

Gestiona suscripciones a eventos (mensajes, timers, signals, conditionals): - subscribeToEvents(context, element): según el tipo de catch event, crea MessageSubscription, TimerSubscription o SignalSubscription. - unsubscribeFromEvents(context): limpia todas las suscripciones del elemento. - triggerEvent(context, eventTrigger): procesa un evento que ha sido disparado.

BpmnCompensationSubscriptionBehaviour

Registra y dispara handlers de compensación: - registerCompensationHandler(context, element): registra un CompensationSubscription cuando una actividad con compensation handler se completa. - triggerCompensation(context): invoca los handlers de compensación registrados en orden inverso.

BpmnStateBehavior

Lee y escribe variables en el state store: - getVariables(context): obtiene las variables del scope actual y sus ancestros. - setVariable(context, name, value): escribe una variable en el scope local. - propagateVariables(context): propaga variables del scope hijo al padre al completar.

BpmnStateTransitionBehavior

Orquesta las transiciones de estado del elemento instance: - transitionToActivated(context): escribe ELEMENT_ACTIVATED y ejecuta finalizeActivation. - transitionToCompleting(context): escribe ELEMENT_COMPLETING. - transitionToCompleted(context): escribe ELEMENT_COMPLETED, toma sequence flows salientes. - transitionToTerminating(context): escribe ELEMENT_TERMINATING. - transitionToTerminated(context): escribe ELEMENT_TERMINATED, notifica al contenedor padre. - takeOutgoingSequenceFlows(context, element): para cada sequence flow saliente, escribe un record SEQUENCE_FLOW_TAKEN.

BpmnDecisionBehavior

Integración con el engine DMN: - evaluateDecision(context, element): parsea el decision ID del elemento, invoca el DmnScalaDecisionEngine, convierte el resultado de FEEL a MessagePack.

BpmnSignalBehavior

Broadcast y suscripción a señales: - throwSignal(context, signalName): emite una señal que activa todos los catch events suscritos. - subscribeToSignal(context, signalName): registra un catch event como listener de una señal.

BpmnUserTaskBehavior

Lifecycle específico de user tasks: - createUserTask(context, element): crea el registro de tarea con asignee, candidateGroups, candidateUsers, dueDate, followUpDate, formKey. - completeUserTask(context): marca la tarea como completada, aplica variables de resultado. - assignUserTask(context, assignee): asigna o reasigna la tarea. - updateUserTask(context, changeset): actualiza propiedades de la tarea (dueDate, etc.).

Procesadores clave en detalle

ExclusiveGatewayProcessor

Split (divergencia): evalúa las condiciones FEEL de cada sequence flow saliente en orden. Toma la primera cuya condición evalúa a true. Si ninguna condición es verdadera y existe un default flow, toma el default. Si no hay default y ninguna condición se cumple → incidente CONDITION_ERROR.

Join (convergencia): es un simple passthrough. El primer token que llega continúa inmediatamente. No hay sincronización.

Característica clave: la transición es instantánea — no hay estado ACTIVATED persistente. El gateway se activa, evalúa, y toma el flow en un solo paso de procesamiento.

ParallelGatewayProcessor

Solo maneja fork (divergencia): activa todos los sequence flows salientes incondicionalmente. Cada flow crea una activación independiente del target.

El join lo maneja SequenceFlowProcessor: cuando un sequence flow llega a un parallel gateway como target, el SequenceFlowProcessor registra el flow incoming en el event scope del gateway. Un mecanismo de conteo verifica si todos los incoming flows han sido tomados. Solo cuando el último flow llega, el gateway se activa y continúa.

SubProcessProcessor

  1. Activación: aplica input mappings (via BpmnVariableMappingBehavior), creando un scope local de variables para el sub-proceso.
  2. Inicio: activa el start event interno del sub-proceso.
  3. Ejecución: los elementos internos se ejecutan normalmente dentro del scope del sub-proceso. Las variables del sub-proceso no son visibles fuera a menos que haya output mappings.
  4. Completación: cuando el end event interno se alcanza, aplica output mappings al scope padre.
  5. Terminación de hijos: si el sub-proceso se termina (por boundary event interrupting, terminación del padre, etc.), todos los hijos activos se terminan recursivamente via onChildTerminated.

BusinessRuleTaskProcessor

Opera en dos modos mutuamente excluyentes:

  1. Modo DMN directo: si el elemento tiene un calledDecisionId, invoca BpmnDecisionBehavior.evaluateDecision() que ejecuta la decisión DMN inline en el engine, sin crear job. El resultado se mapea a variables via output mappings. Binding types soportados: latest, deployment, versionTag.

  2. Modo job worker: si el elemento tiene un taskDefinition (type), se comporta como un service task — crea un job via BpmnJobBehavior que será recogido por un job worker externo.

La selección del modo es determinística: si existe calledDecisionId, se usa DMN directo; si no, se usa job worker. No se pueden combinar ambos.

UserTaskProcessor

Lifecycle específico distinto de los service tasks:

  1. Activación: aplica input mappings y crea el user task record con metadata (asignee, candidateGroups, candidateUsers, dueDate, followUpDate, formKey/formId).
  2. Estado activo: el task permanece en ACTIVATED esperando interacción humana. Soporta operaciones intermedias: assign, claim, unclaim, update.
  3. Completación: un usuario (via API) completa la tarea, opcionalmente con variables de resultado. Se aplican output mappings y el procesador continúa al siguiente elemento.
  4. Cancelación: boundary events (timer, message) pueden interrumpir el user task, terminándolo.

El UserTaskProcessor usa BpmnUserTaskBehavior para la gestión del estado del task y BpmnJobBehavior en el caso de task listeners (JobKind.TASK_LISTENER).