ADR 021: Shared Definition APIs
Status
Accepted — amends ADR 003
Context
ADR 003 nests every section inside the Process API of one process. That fits what belongs to a single process — element ids, timers, variables, call activities, the flow — but not the identifiers the engine resolves across process boundaries: job types, message names, signal names, errors and escalations. Two processes served by the same worker or subscribing to the same message got two independent constants (AProcessApi.ServiceTasks.X, BProcessApi.ServiceTasks.X) for one value, and nothing checked that they stayed consistent.
Errors had a second problem: constants were named after the error name alone, so two errors with the same name and different codes — different errors to the engine, which matches by code — collapsed into one constant and one of them was silently lost.
Decision
- Shared definitions are generated once per run.
ServiceTasks,Messages,Signals,ErrorsandEscalationseach become a top-level type in their own file, in the configuredpackagePath, next to the Process APIs. A file is only generated when at least one process has a matching element. - Deduplicated by value. A value used by several processes yields one constant. Root elements are collected from all merged models, so the first name in sorted order wins when several map to the same value.
- The Process API keeps what is process-bound:
PROCESS_ID,PROCESS_ENGINE,Elements,CallActivities,Timers,Variables,Flow/Variants. - Errors and escalations are named
NAME_CODE(ERROR_INVALID_MAIL_500); without a code, the name alone. - Collisions are checked across all processes. Two different values that normalize to the same constant name — in one process or in two — fail generation.
SharedDefinitionCollisionRuleis a mandatory cross-model rule;CollisionDetectionRulekeeps checking the process-local sections. - Variable names are shared too.
ProcessVariablesholds each variable name of the run once as a raw string constant. Variables live on the process instance, but several processes use the same names (anorderIdacross all order processes), so one constant makes every usage findable across processes. The direction stays process-bound: each node's typedVariableswrap the shared constant asInput,OutputorInOut. The file is namedProcessVariables, notVariables, since each node's ownVariablesholder would shadow it. As for the other kinds,orderIdandorder_idfold to one constant and fail generation, now across processes as well. - No flag. This is the layout of 6.0.0; the old nesting is not kept as an option.
Consequences
- A Process API is no longer self-contained: it belongs together with the shared files of the same run.
- The shared files are named after their kind, not after a process. Two generation runs writing into the same
packagePathoverwrite each other's shared files, so each run needs its own package. - The generic type names (
ServiceTasks,Errors, …) can clash with user types in the same package. They are package-scoped, so moving the generated code to its own package resolves that. - A shared file that is no longer produced — e.g. after removing the last signal — would linger in the output folder, as a renamed process's API already did before. The generator therefore removes the files it owns (header-carrying files in the
packagePath) but no longer produces, which makes one package per run mandatory: a second run would remove the first run's Process APIs. NAME_CODEis redundant for textual codes that repeat the name (INVALID_MAIL/INVALID_MAIL).- Breaking for every 5.x user of the nested registries.