What it does in BusinessWorks
A Catch activity is a fault handler, marked <pd:handler>true</pd:handler> and attached to a
process or to a group. Designer wires it independently of the ordinary flow: it is not reached by a
transition from the activities it protects, it is attached to the scope and triggered whenever an
activity inside that scope faults. <config><fault> names the fault type it matches, or
<catchAll>true</catchAll> matches anything. From the Catch onward, the process continues as a
normal transition chain, typically into logging, a notification, and sometimes a
Rethrow.
A process can carry several Catch handlers at different scopes, and the most specific match wins,
the same nesting a try/catch block gives you in any language with structured exception handling.
The Camel equivalent
<pd:activity name="Catch Every Fault">
<pd:type>com.tibco.pe.core.CatchActivity</pd:type>
<pd:resourceType>ae.activities.catch</pd:resourceType>
<pd:handler>true</pd:handler>
<config>
<catchAll>true</catchAll>
</config>
<pd:inputBindings/>
</pd:activity>// generated only if a transition targets this node,
// see below for why that is rarely true
.log("Catch Every Fault: catch boundary
(modeled by global onException)")Where the semantics diverge
The rule only runs if the route graph reaches the node. The generator builds one route per
process by walking transitions from the Start activity. A Catch handler attached to a process or
group in the way BusinessWorks normally attaches one, through the handler flag rather than a
transition into it, has no incoming edge in that graph. A node the walk never reaches is never
emitted: not as a step, not as a TODO_HUMAN, not as anything. The handler is silently absent from
the route, and nothing in the output says a handler existed.
When it is reached, it becomes one log line and nothing else. The rule that fires in that case
emits .log(...) with a fixed message and points at “global onException”, but this activity does
not create one. Global exception handling is written by a separate part of the generator, described
below, and it is not scoped to the fault types a given Catch declared. <fault> is never read.
Fault-type matching does not carry over. A process with three Catch handlers for three fault types collapses, where reached at all, to the same log line three times, with no way to tell from the output which fault each one was for.
Nesting is lost. Which scope a handler was attached to (the whole process, or one group inside it) decided what it could catch. The generated route has no equivalent boundary.
Wherever a process relies on scoped fault handling, and most non-trivial ones do, the real error
model has to be rebuilt as doTry/doCatch blocks or per-route onException clauses that match on
the actual exception types your other translated activities throw, not on the log line this rule
leaves behind.
What the toolchain does
An unconditional rule when the node is reached: .log(LoggingLevel.INFO, "<name>: catch boundary (modeled by global onException)"). It does not read <fault> or <catchAll>, and does not attach
an exception clause of its own.
Separately, the generator writes one fault-policy RouteBuilder per operation with three fixed
onException clauses (a business fault class, a technical fault class and Exception), each
.handled(false), logging and optionally forwarding to direct:errorEvent. That policy is generic to the operation,
not derived from any Catch activity in the source process; it exists whether or not the process had
one.