orbit-code-ai 0.1.20 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,117 +1,178 @@
1
1
  # Error Handling
2
2
 
3
- Central error handling is provided by `ErrorHandler.subflow` + `ErrorHandler.esql`. Every flow MUST wire its exception terminal to the error handler.
3
+ Central error handling is provided by `ErrorHandler.subflow` (+ `ErrorHandler.esql`, ~43 KB). Every flow wires its node **failure/catch terminals** to the matching `ErrorHandler` input terminal. The handler classifies the error, logs it for audit, and builds a standardized ESB response.
4
4
 
5
5
  ---
6
6
 
7
- ## ErrorHandler.subflow
7
+ ## Two error channels
8
+
9
+ There are two distinct mechanisms — don't confuse them:
10
+
11
+ 1. **Business errors** (validation, expected error codes) — set the code yourself and let the
12
+ business-error path build the response:
13
+ ```esql
14
+ SET Environment.Variables.MWResponse.status = '<error_code>'; -- e.g. an ESB_ERROR_CODES value
15
+ ```
16
+ `ESBBusinessErrorResponse` reads `Environment.Variables.MWResponse.status` (defaulting to
17
+ `'99999999'`) and calls `CreateEsbXMLResponseHeaderFromRoot(...)` to emit the response header.
18
+ Do **not** `THROW USER EXCEPTION` for business validation.
19
+
20
+ 2. **Technical exceptions** — wire the node's **failure** terminal to `ErrorHandler`. The exception
21
+ list is parsed, logged, and turned into a fault/response. The handler distinguishes the error
22
+ class via `Environment.Variables.esb.errorType`, set by the small `ErrorHandler_Handle*` compute
23
+ modules (one per input terminal):
24
+
25
+ | Input terminal | Handler module | `esb.errorType` set |
26
+ |---|---|---|
27
+ | `Failure` (`WSFailure`) | `ErrorHandler_HandleFailure` | `Failure` |
28
+ | `Fault` (`WSFault`) | `ErrorHandler_HandleFault` | `Fault` |
29
+ | `ValidationFailure` | `ErrorHandler_HandleValidationFailure` | `ValidationFailure` |
30
+ | `FileFailure` | `ErrorHandler_HandleFileFailure` | `FileFailure` |
31
+ | `MQInputFailure` | `ErrorHandler_HandleMQInputFailure` | `MQInputFailure` |
32
+ | `MQInputCatch` | `ErrorHandler_HandleMQInputCatch` | `MQInputCatch` (sets `EXCEPTION_CAUGHT`) |
33
+ | `FileInputCatch` | `ErrorHandler_HandleFileInputCatch` | `FileInputCatch` (sets `EXCEPTION_CAUGHT`) |
34
+
35
+ `ErrorHandler_CreateGeniricRs` then builds the response from `esb.errorType` + the active backend
36
+ adapter flag (below).
8
37
 
9
- **Purpose**: Catches all exceptions, builds a standardized error response, logs it, and routes to dead-letter or returns a business error.
38
+ ---
39
+
40
+ ## ErrorHandler.subflow terminals
41
+
42
+ Wire to the input terminal that matches the failing node:
10
43
 
11
- **Internal flow**:
12
44
  ```
13
- Exception caught
14
-
15
- ErrorHandler.esql (build error structure)
16
-
17
- ErrorHandler_IsExceptionCaught.esql (filter: already handled?)
18
-
19
- LogError subflow (audit the error)
20
-
21
- [Route based on adapter type]
22
- ├── MQ_Dead_Output_Node (async flows)
23
- └── MWBusinessErrorResponse (sync/HTTP flows)
45
+ InTerminal.Input -- generic
46
+ InTerminal.ValidationFailure / InTerminal.FileValidationFailure
47
+ InTerminal.WSFailure / InTerminal.WSFault
48
+ InTerminal.MQInputFailure / InTerminal.MQInputCatch
49
+ InTerminal.FileFailure / InTerminal.FileInputCatch
50
+ InTerminal.SystemDown
51
+ InTerminal.httphandlefail / InTerminal.httphandlefault
52
+
53
+ OutTerminal.Output
24
54
  ```
25
55
 
26
- **ESQL modules**:
27
- | Module | Purpose |
28
- |---|---|
29
- | `ErrorHandler.esql` | Main: 43KB builds error structure, maps error codes per backend |
30
- | `ErrorPoint.esql` | Create error message structure from exception |
31
- | `ErrorHandler_IsExceptionCaught.esql` | Filter: prevent double-handling |
32
- | `ErrorHandler_SetExceptionCaught.esql` | Mark exception as handled |
33
- | `ErrorHandler_IsFileSchemaValidationOccured.esql` | Detect file schema validation errors |
34
- | `ErrorHandler_PrepareFileDataForAudit.esql` | Prepare file error data for audit |
35
- | `ESBBusinessErrorResponse.esql` | Build ESB-standard business error response |
56
+ Internally it routes through:
57
+ - `LogError.subflow` audit-logs the error (uses `ErrorPoint` to build the error/audit record).
58
+ - `MWBusinessErrorResponse.subflow` — emits the synchronous ESB error response to the caller.
59
+ - `MQ_Dynamic_Output_Node.subflow` — async/dead routing.
60
+ - `ErrorHandler_IsAtomicService` (FILTER, gated by `IsAtomic EXTERNAL BOOLEAN`).
36
61
 
37
62
  ---
38
63
 
39
- ## MWBusinessErrorResponse.subflow
64
+ ## ESQL modules
40
65
 
41
- **Purpose**: Returns a structured business error response to the caller (used in sync/HTTP flows).
66
+ | Module | Type | Purpose |
67
+ |---|---|---|
68
+ | `ErrorHandler.esql` › `ErrorHandler_CreateGeniricRs` | COMPUTE | Builds the error response from `esb.errorType` + backend flag |
69
+ | `ErrorHandler.esql` › `ErrorHandler_Handle*` | COMPUTE | Tag `esb.errorType` per terminal (table above) |
70
+ | `ErrorHandler.esql` › `ErrorHandler_IsAtomicService` | FILTER | Routes atomic vs non-atomic (`IsAtomic`) |
71
+ | `ErrorHandler_IsExceptionCaught.esql` | FILTER | Returns the `EXCEPTION_CAUGHT` SHARED flag (prevent double-handling) |
72
+ | `ErrorHandler_SetExceptionCaught.esql` | COMPUTE | Resets `EXCEPTION_CAUGHT = FALSE` |
73
+ | `ErrorHandler_IsFileSchemaValidationOccured.esql` | — | Detect file schema-validation errors |
74
+ | `ErrorHandler_PrepareFileDataForAudit.esql` | COMPUTE | Prepare file error data for audit |
75
+ | `ErrorPoint.esql` › `ErrorPoint_PrepareErrorMsg` | COMPUTE | Build the error/audit record (see below) |
76
+ | `ESBBusinessErrorResponse.esql` › `ESBBusinessErrorResponse_handleRs` | COMPUTE | Business-error response from `MWResponse.status` |
77
+
78
+ `EXCEPTION_CAUGHT` is a `SHARED BOOLEAN` set by the `*Catch` handlers; `ErrorHandler_IsExceptionCaught`
79
+ reads it and `ErrorHandler_SetExceptionCaught` clears it, so an MQ/File input catch isn't processed twice.
42
80
 
43
- **When to use**: REST/HTTP flows where the caller expects a JSON error response.
81
+ ---
44
82
 
45
- **Response structure**:
46
- ```xml
47
- <ResponseStatus>
48
- <Code>XXXXXXXX</Code>
49
- <Status>Error</Status>
50
- <EnglishMsg>Human readable message</EnglishMsg>
51
- </ResponseStatus>
52
- ```
83
+ ## Backend adapter flags
53
84
 
54
- ---
85
+ Which backend produced the error is selected by an `EXTERNAL BOOLEAN` flag, set `TRUE` at the
86
+ node/BAR level for the adapter in use (all default `FALSE`). `ErrorHandler_CreateGeniricRs` branches
87
+ on these:
55
88
 
56
- ## Error Codes by Backend System
89
+ ```esql
90
+ DECLARE IsFrotEndAdapter EXTERNAL BOOLEAN FALSE; -- front-end SOAP fault
91
+ DECLARE IsFrontEndJSONAdapter EXTERNAL BOOLEAN FALSE; -- front-end JSON fault
92
+ DECLARE IsT24Adapter EXTERNAL BOOLEAN FALSE;
93
+ DECLARE IsT24OFENQAdapter EXTERNAL BOOLEAN FALSE;
94
+ DECLARE IsODMWSAdapter EXTERNAL BOOLEAN FALSE;
95
+ DECLARE IsNICAdapter EXTERNAL BOOLEAN FALSE;
96
+ DECLARE IsNIWSAdapter EXTERNAL BOOLEAN FALSE;
97
+ DECLARE IsMEPSWSAdapter EXTERNAL BOOLEAN FALSE;
98
+ DECLARE IsICBSWSAdapter EXTERNAL BOOLEAN FALSE;
99
+ DECLARE IsA2AWSAdapter EXTERNAL BOOLEAN FALSE;
100
+ DECLARE IsACHWSAdapter EXTERNAL BOOLEAN FALSE;
101
+ DECLARE IsUnifonicAdapter EXTERNAL BOOLEAN FALSE;
102
+ DECLARE IsMLSDWSAdapter EXTERNAL BOOLEAN FALSE;
103
+ DECLARE IsCapptionsWSAdapter EXTERNAL BOOLEAN FALSE;
104
+ DECLARE IsHyperpayWSAdapter EXTERNAL BOOLEAN FALSE;
105
+ DECLARE IsAtomic EXTERNAL BOOLEAN TRUE;
106
+ ```
57
107
 
58
- Defined as constants in `CommonUtils.esql`:
108
+ For each backend, the response code is taken from properties with a hardcoded fallback, using four
109
+ severities gated by an availability check:
59
110
 
60
- | Constant | Value | Backend |
61
- |---|---|---|
62
- | `ESB_SUCCESS_RESPONSE_CODE` | `'00000000'` | All |
63
- | `ESB_RUNTIME_TECHNICAL_ERROR_CODE` | `'99999999'` | All (generic) |
64
- | `ESB_MIDDLEWARE_DATABASE_ERROR_RESPONSE_CODE` | `'E0199998'` | DB errors |
111
+ ```
112
+ Environment.Properties.<Adapter>.<Flow>.Variables.IsSystemAvailable -- false → SystemDown code
113
+ Environment.Properties.<Adapter>.<Flow>.Variables.<BE>SystemDownErrorCode -- e.g. 'ODM99996'
114
+ Environment.Properties.<Adapter>.<Flow>.Variables.<BE>FailureErrorCode -- esb.errorType='Failure'
115
+ Environment.Properties.<Adapter>.<Flow>.Variables.<BE>FaultErrorCode -- esb.errorType='Fault'
116
+ Environment.Properties.<Adapter>.<Flow>.Variables.<BE>TechnicalErrorCode -- else
117
+ ```
65
118
 
66
- Additional backend-specific codes exist for:
67
- - **T24**: Core banking errors
68
- - **NIWS**: National Information and Workflow System
69
- - **ODM**: Operational Decision Manager
70
- - **Unifonic**: SMS/notification service
71
- - **MLSD**: Ministry of Labor and Social Development
72
- - **ICBS**: Core banking system
119
+ Backend code prefixes seen in defaults: T24 (`Create_esbXML_Response_Header_Using_Backend_Code('T24'…)`),
120
+ `ODM999xx`, `UNI999xx`, `NIC999xx`, `MLSD999x`, `CAPP999x`, `HYPP00xx`, `NI9999xx`, `MEPS999x`,
121
+ `ICBS999x`, `A2A999x`, `ACH999x`. SOAP-fault backends map via `..._Using_Backend_Code('<BE>WS', code, …)`
122
+ against `ESB_ERROR_CODES`. When `Header.DebugFlag = '1'`, the raw backend error + parsed exception
123
+ text are surfaced under `Header.BackendError.ErrorCode` / `.ErrorDescription`.
73
124
 
74
- Read `ErrorHandler.esql` directly for the full mapping if you need specific codes.
125
+ The response itself is built with the CommonUtils procedures `Create_esbXML_Response_Header`,
126
+ `Create_esbXML_Response_Header_Using_Backend_Code`, and `CreateEsbXMLResponseHeaderFromRoot`, setting
127
+ `Header.ResponseStatus.{Status='Error', Code, EnglishMsg, ArabicMsg}`. Front-end adapters instead emit
128
+ a SOAP/JSON fault (`GenerateSOAPFault` / `GenerateJSONFault`) with HTTP reply status `500`.
75
129
 
76
130
  ---
77
131
 
78
- ## Wiring the Error Handler in a New Flow
132
+ ## Error codes
79
133
 
80
- Every node that can fail must connect its **failure/exception terminal** to `ErrorHandler`:
134
+ ESB codes are `EXTERNAL CHARACTER` constants in `CommonUtils.esql` (see [common-utils](common-utils.md)):
135
+ `ESB_SUCCESS_RESPONSE_CODE` `'00000000'`, `ESB_RUNTIME_TECHNICAL_ERROR_CODE` `'99999999'`,
136
+ `ESB_MIDDLEWARE_RUNTIME_ERROR_RESPONSE_CODE` `'99999999'`, `ESB_MIDDLEWARE_DATABASE_ERROR_RESPONSE_CODE`
137
+ `'E0199998'`, plus channel codes `'E9009999'`/`'55555555'`/`'44444444'` and `'E5500003'`. Localized
138
+ descriptions come from `dbo.ESB_ERROR_CODES` via `getEsbErrorCodeDescriptionFrom` /
139
+ `getEsbChannlsErrorCodeDescriptionFrom` / `getBackendEsb_MapErrorCode`. Per-backend default codes live
140
+ in the adapter's properties (above), not in CommonUtils.
81
141
 
82
- ```
83
- [Any Node]
84
- │ failure terminal
85
-
86
- ErrorHandler.subflow
87
-
88
- ├──[MQ flow]──→ MQ_Dead_Output_Node
89
- └──[HTTP flow]─→ MWBusinessErrorResponse
90
- ```
142
+ ---
91
143
 
92
- **ESQL DECLARE for ErrorHandler behavior**:
93
- ```esql
94
- -- Set which backend adapter this flow uses (controls error code mapping)
95
- DECLARE IsT24Adapter EXTERNAL BOOLEAN FALSE;
96
- DECLARE IsODMWSAdapter EXTERNAL BOOLEAN FALSE;
97
- DECLARE IsFrontEndJSONAdapter EXTERNAL BOOLEAN FALSE;
98
- DECLARE IsNIWSAdapter EXTERNAL BOOLEAN FALSE;
99
- DECLARE IsUniFonicAdapter EXTERNAL BOOLEAN FALSE;
100
- DECLARE IsMLSDAdapter EXTERNAL BOOLEAN FALSE;
101
- DECLARE IsICBSAdapter EXTERNAL BOOLEAN FALSE;
102
- ```
144
+ ## ErrorPoint (error/audit record)
103
145
 
104
- Set the appropriate flag to `TRUE` at the node level to get correct error codes for that backend.
146
+ `ErrorPoint_PrepareErrorMsg` is the **internal** module the error/audit path uses it is not a
147
+ user-set API. It builds `OutputRoot.XMLNSC.Error` with:
148
+
149
+ - `errorName` = `'Error in Application: ' || ApplicationLabel || ' in Message Flow: ' || MessageFlowLabel`
150
+ - `errorMessage` = parsed exception text (via `PARSEExceptionList`), or the raw bitstream when no exception list
151
+ - `auditHeader` = requestId, timestamp, applicationName, messageFlowName, brokerName, executionGroupName,
152
+ logType `'Error'`, channelId, userName, serviceCode, sessionId, channelReqTime, requestMessage
153
+
154
+ It falls back to `Environment.ESB.Framework.ErrorHandler.Header.*` for header fields when the inbound
155
+ message header is absent.
105
156
 
106
157
  ---
107
158
 
108
- ## ErrorPoint Usage
159
+ ## Wiring a new flow
160
+
161
+ ```
162
+ [Any processing node]
163
+ │ failure terminal
164
+
165
+ ErrorHandler.subflow (InTerminal matching the node/error class)
166
+ ├─ LogError.subflow → audit
167
+ ├─ MWBusinessErrorResponse.subflow → sync ESB response to caller
168
+ └─ MQ_Dynamic_Output_Node.subflow → async/dead routing
169
+ ```
109
170
 
110
- Use `ErrorPoint.esql` when you need to manually create an error structure (e.g., business validation failure before calling a backend):
171
+ For an expected business/validation error, prefer the business channel:
111
172
 
112
173
  ```esql
113
- -- Set error details on the Environment before routing to ErrorHandler
114
- SET Environment.ErrorDetails.Code = 'XXXXXXXX';
115
- SET Environment.ErrorDetails.EnglishMsg = 'Validation failed: ...';
116
- -- Then propagate to ErrorHandler via failure terminal
174
+ -- validation failed: set the ESB code and let the business-error path respond
175
+ SET Environment.Variables.MWResponse.status = 'E5500003';
176
+ PROPAGATE TO TERMINAL 'out2'; -- route to the business-error branch
177
+ RETURN FALSE;
117
178
  ```
@@ -10,26 +10,15 @@ Used for outbound HTTP calls (to backends or internal services) and for chaining
10
10
 
11
11
  **Supported backends**: T24, NIWS, ODM, Unifonic, MLSD, ICBS, and any REST/SOAP service.
12
12
 
13
- **ESQL helpers**:
14
- | Module | Purpose |
15
- |---|---|
16
- | `HTTPResponseAdapter_CheckCallType.esql` | Determine INTERNAL vs EXTERNAL call |
17
- | `InternalHTTPRequestAdapter_Remove_MQRFH2.esql` | Strip MQRFH2 headers before HTTP call |
18
-
19
- **ESQL DECLARE flags** (set at node level):
20
- ```esql
21
- DECLARE IsT24Adapter EXTERNAL BOOLEAN FALSE;
22
- DECLARE IsODMWSAdapter EXTERNAL BOOLEAN FALSE;
23
- DECLARE IsFrontEndJSONAdapter EXTERNAL BOOLEAN FALSE;
24
- DECLARE IsNIWSAdapter EXTERNAL BOOLEAN FALSE;
25
- DECLARE IsUniFonicAdapter EXTERNAL BOOLEAN FALSE;
26
- DECLARE IsMLSDAdapter EXTERNAL BOOLEAN FALSE;
27
- DECLARE IsICBSAdapter EXTERNAL BOOLEAN FALSE;
28
- ```
13
+ **Node properties** (EXTERNAL): `ServiceURL`, `TimeoutInSec`.
29
14
 
30
- Set exactly ONE of these to `TRUE` to get correct request formatting and error code mapping for that backend.
15
+ **URL/endpoint**: set the node `ServiceURL`, or read the target from the
16
+ `BankIdForRoutingService` properties group (see below).
31
17
 
32
- **URL/endpoint**: Set in `Environment.Destination.HTTP.RequestURL` before calling this subflow, or configure in `BankIdForRoutingService` properties group.
18
+ > The per-backend `Is<Backend>Adapter` flags (`IsT24Adapter`, `IsODMWSAdapter`, `IsUnifonicAdapter`,
19
+ > `IsMLSDWSAdapter`, `IsICBSWSAdapter`, …) are **not** declared on `HTTPRequestAdapter`. They live on
20
+ > the error path (`ErrorHandler_CreateGeniricRs`) where they select backend-specific error-code mapping.
21
+ > See [error-handling](error-handling.md) for the full, correctly-named list.
33
22
 
34
23
  ---
35
24
 
@@ -37,8 +26,10 @@ Set exactly ONE of these to `TRUE` to get correct request formatting and error c
37
26
 
38
27
  **Purpose**: Processes the HTTP response from a backend call, normalizes it to the standard ESB response structure.
39
28
 
40
- **ESQL helper**: `HTTPResponseAdapter_CheckCallType.esql`
41
- - Routes differently based on whether it was an `INTERNAL` or `EXTERNAL` call
29
+ **ESQL helper**: `HTTPResponseAdapter_CheckCallType.esql` (FILTER)
30
+ - Reads `Root.MQRFH2.usr.http.reply.callType`: returns FALSE for `'EXTERNAL'`, TRUE otherwise.
31
+ - The call type is stamped upstream by `InternalHTTPRequestAdapter_SetCallType.esql`, which sets
32
+ `MQRFH2.usr.http.reply.callType = 'INTERNAL'` (and the reply id) for internal calls.
42
33
 
43
34
  **Always pair with** `HTTPRequestAdapter` — use both or neither.
44
35
 
@@ -18,25 +18,35 @@ All input adapters live in `Qiwa/Framework/Lib/`. Use them as the entry point of
18
18
  **ESQL helper modules used**:
19
19
  | Module | Purpose |
20
20
  |---|---|
21
- | `MQ_Input_Node_IsAuditEnabled.esql` | Filter: check if audit is on |
22
- | `MQ_Input_Node_IsPropertiesEnabled.esql` | Filter: check if properties loaded |
23
- | `MQ_Input_Node_IsRetryEnabled.esql` | Filter: check if retry is on |
24
- | `MQ_Input_Node_IsRollBackEnabled.esql` | Filter: check if rollback is on |
25
- | `MQ_Input_Node_PrepareAuditMessage.esql` | Compute: build audit payload |
21
+ | `MQ_Input_Node.esql` (`MQ_Input_Node_Compute`, `Filter_IS_Audit_Enabled_Input_Node`) | Main compute + input audit gate (`ENABLE_AUDIT_INPUT`) |
22
+ | `MQ_Input_Node_IsAuditEnabled.esql` | Filter: `Logging.LogEnabled OR Logging.AuditEnabled` |
23
+ | `MQ_Input_Node_IsPropertiesEnabled.esql` | Filter: is PropertyReader enabled (`PROPERTIES_ENABLED`) |
24
+ | `MQ_Input_Node_IsRetryEnabled.esql` | Filter: `Retry.RetryEnabled` |
25
+ | `MQ_Input_Node_IsRollBackEnabled.esql` | Filter: `ROLL_BACK_TRANSACTION` |
26
+ | `MQ_Input_Node_SetMsgUIDinEnv.esql` | Compute: stash message UID in Environment |
27
+ | `MQ_Input_Node_PrepareAuditMessage.esql` | Compute: build audit payload → `LogAudit` |
26
28
 
27
- **Configuration flags** (set in Properties XML under `Logging` group):
28
- ```
29
- AuditEnabled TRUE/FALSE
30
- LogEnabled TRUE/FALSE
31
- RetryEnabled TRUE/FALSE (also under Retry group)
32
- ValidationEnabled TRUE/FALSE (under SchemaValidation group)
33
- ```
29
+ (`MQ_Input_Node_IsAuditEnabled.esql` also defines `MQ_Input_Node_IsSchemaValidationEnabled` and `MQ_OutputNode_IsServiceOut`.)
30
+
31
+ **Configuration (Properties XML)** — each filter reads its property, and if the flow's property group
32
+ is absent it falls back to the node EXTERNAL default:
33
+
34
+ | Property (group) | EXTERNAL fallback |
35
+ |---|---|
36
+ | `Logging.LogEnabled` / `Logging.AuditEnabled` | `LOG_ENABLED` (also `ENABLE_AUDIT_INPUT`) |
37
+ | `Retry.RetryEnabled` | `RETRY_ENABLED` |
38
+ | `SchemaValidation.ValidationEnabled` | `SCHEMA_VALIDATION_ENABLED` |
39
+ | (rollback — flag only) | `ROLL_BACK_TRANSACTION` |
40
+ | (PropertyReader on/off — flag only) | `PROPERTIES_ENABLED` |
34
41
 
35
- **ESQL DECLARE for this node**:
42
+ **ESQL EXTERNAL flags on this node** (real names — all default as noted):
36
43
  ```esql
37
- DECLARE IsAuditEnabled EXTERNAL BOOLEAN FALSE;
38
- DECLARE IsRetryEnabled EXTERNAL BOOLEAN FALSE;
39
- DECLARE IsRollBackEnabled EXTERNAL BOOLEAN FALSE;
44
+ DECLARE PROPERTIES_ENABLED EXTERNAL BOOLEAN FALSE;
45
+ DECLARE LOG_ENABLED EXTERNAL BOOLEAN FALSE;
46
+ DECLARE SCHEMA_VALIDATION_ENABLED EXTERNAL BOOLEAN FALSE;
47
+ DECLARE RETRY_ENABLED EXTERNAL BOOLEAN FALSE;
48
+ DECLARE ROLL_BACK_TRANSACTION EXTERNAL BOOLEAN FALSE;
49
+ DECLARE ENABLE_AUDIT_INPUT EXTERNAL BOOLEAN TRUE;
40
50
  ```
41
51
 
42
52
  **When to use**: Any flow that reads from an IBM MQ queue asynchronously.
@@ -8,9 +8,13 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
8
8
 
9
9
  **Purpose**: Standard MQ output. Writes message to a target queue.
10
10
 
11
- **ESQL module**: `MQ_Output_Node.esql`
12
- - Copies message headers (`CopyMessageHeaders`)
13
- - Sets MQ destination queue from `Environment.Destination.MQ.DestinationData.queueName`
11
+ **ESQL module**: `MQ_Output_Node.esql` (`MQ_Output_Node_Compute` + `Filter_Is_Audit_Enabled_Output_Node`)
12
+ - Copies headers, then defaults `MQMD.CorrelId` to `MQMD.MsgId` when empty/zero
13
+ - Applies `MQMD.Priority` from `Environment.Properties.{ApplicationLabel}.{flowName}.Priority.Priority` when present
14
+ - Optional output audit gated by EXTERNAL `ENABLE_AUDIT_OUTPUT` (default `TRUE`)
15
+ - It does **not** choose the destination queue — that is set upstream on
16
+ `LocalEnvironment.Destination.MQ.DestinationData[1].queueName` (by `SetQueues`,
17
+ `MQ_OutputNode_IsServiceOut`, or `MQ_OutputNode_IsDeadFlow`)
14
18
 
15
19
  **When to use**: Standard async MQ output for any request or response message.
16
20
 
@@ -20,11 +24,14 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
20
24
 
21
25
  **Purpose**: Routes failed/unprocessable messages to a backout/dead-letter queue.
22
26
 
23
- **ESQL module**: `MQ_OutputNode_IsDeadFlow.esql`
27
+ **ESQL module**: `MQ_OutputNode_IsDeadFlow.esql` (FILTER, EXTERNAL `DEAD_FLOW BOOLEAN FALSE`)
28
+ - When `DEAD_FLOW` is TRUE → dead path. Otherwise it sets the destination from
29
+ `Root.MQRFH2.usr.queue.distinationQueue` (sic) and returns FALSE.
24
30
 
25
31
  **When to use**: Always wire this as the terminal node on the error path of every MQ flow.
26
32
 
27
- **Queue naming**: `<ORIGINAL_QUEUE_NAME>.BACKOUT`
33
+ **Queue naming**: backout/dead queues follow the `<ORIGINAL_QUEUE_NAME>.BACKOUT` convention (see
34
+ [naming-conventions](../config/naming-conventions.md)).
28
35
 
29
36
  ---
30
37
 
@@ -34,7 +41,7 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
34
41
 
35
42
  **When to use**: Flows where the destination queue varies per message (e.g., routing based on `ServiceCode`).
36
43
 
37
- **How it works**: Reads queue name from `Environment.Destination.MQ.DestinationData.queueName` — set this dynamically in your compute ESQL before calling this subflow.
44
+ **How it works**: Reads the queue name from `LocalEnvironment.Destination.MQ.DestinationData[1].queueName` — set this dynamically in your compute ESQL (via `OutputLocalEnvironment.Destination...`) before this subflow.
38
45
 
39
46
  ---
40
47
 
@@ -66,8 +73,8 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
66
73
 
67
74
  **Purpose**: Makes outbound HTTP/SOAP calls to backend services.
68
75
 
69
- **ESQL helper**: `HTTPResponseAdapter_CheckCallType.esql`
70
- - Determines `INTERNAL` vs `EXTERNAL` call type
76
+ **Node properties**: EXTERNAL `ServiceURL`, `TimeoutInSec`. (Call-type detection lives in
77
+ `HTTPResponseAdapter`, not here see [http-adapters](http-adapters.md).)
71
78
 
72
79
  **When to use**: Any flow that calls an external REST or SOAP service (T24, NIWS, ODM, Unifonic, MLSD, etc.).
73
80
 
@@ -109,16 +116,16 @@ All output adapters live in `Qiwa/Framework/Lib/`. Use them as the exit point of
109
116
 
110
117
  ---
111
118
 
112
- ## ESQL Copy Utilities (used in all adapters)
119
+ ## ESQL Copy Utilities
113
120
 
114
- Every output adapter uses these standard procedures from `copy_Compute.esql`:
121
+ Every framework module defines its own `CopyMessageHeaders()` and `CopyEntireMessage()` procedures
122
+ inline (they are not imported from a shared module):
115
123
 
116
124
  ```esql
117
- -- Copy all MQ and transport headers
118
- CALL CopyMessageHeaders();
119
-
120
- -- Copy entire message tree
121
- CALL CopyEntireMessage();
125
+ CALL CopyMessageHeaders(); -- copy header folders 1..N-1 (preserves MQMD, MQRFH2)
126
+ CALL CopyEntireMessage(); -- SET OutputRoot = InputRoot;
122
127
  ```
123
128
 
124
- Always call `CopyMessageHeaders()` before modifying output to preserve MQ metadata (MQMD, MQRFH2).
129
+ `copy_Compute.esql` is a ready-made generic copy COMPUTE node it calls both procedures and also
130
+ copies `LocalEnvironment.Wildcard.WildcardMatch`. Use it when you just need a pass-through copy node.
131
+ Always copy headers before modifying output to preserve MQ metadata.
@@ -26,8 +26,12 @@
26
26
 
27
27
  Properties are accessed via the path:
28
28
  ```
29
- Environment.Properties.{ApplicationLabel}.{FlowName}.{Group}.{PropertyName}
29
+ Environment.Properties.{ApplicationLabel}.{flowName}.{Group}.{PropertyName}
30
30
  ```
31
+ where `ApplicationLabel` is the broker built-in (application name) and `flowName` is derived from the
32
+ built-in `MessageFlowLabel` via `getFlowNameWithouSchema(Environment.FlowNameSplit)` — both are
33
+ resolved at runtime, not hardcoded. Framework filters guard against the group being absent and fall
34
+ back to the node's EXTERNAL default (e.g. `LOG_ENABLED`, `RETRY_ENABLED`).
31
35
 
32
36
  Examples:
33
37
  ```esql
@@ -66,24 +70,32 @@ These tokens in property values are replaced at runtime:
66
70
 
67
71
  | Token | Replaced With |
68
72
  |---|---|
69
- | `${broker.name}` | ACE broker/integration node name |
70
- | `${execution.group}` | Execution group / integration server name |
71
- | `${flow.name}` | Message flow name |
72
- | `${application.name}` | Application name |
73
+ | `${broker.name}` | ACE broker/integration node name (`BrokerName`) |
74
+ | `${execution.group}` | Execution group / integration server name (`ExecutionGroupLabel`) |
75
+ | `${flow.name}` | Message flow name (`MessageFlowLabel`) |
76
+
77
+ (Only these three tokens are substituted by `PropertyReader_LoadProperties`.)
73
78
 
74
79
  ---
75
80
 
76
- ## ESQL Node Properties for PropertyReader
81
+ ## PropertyReader node properties
82
+
83
+ `PropertyReader_LoadProperties.esql` declares these EXTERNAL (user-defined) properties — set them on the PropertyReader subflow node:
77
84
 
78
85
  ```esql
79
- -- Required EXTERNAL declarations in the module using PropertyReader
80
- DECLARE ApplicationLabel EXTERNAL CHARACTER '';
81
- DECLARE PropertiesFileName EXTERNAL CHARACTER '';
86
+ DECLARE PropertyFilename EXTERNAL CHARACTER '*'; -- the XML config file
87
+ DECLARE PropertiesGroup EXTERNAL CHARACTER '*'; -- which group(s) to load
88
+ DECLARE LogicalTreePath EXTERNAL CHARACTER 'Environment'; -- target tree (must start Environment. or OutputLocalEnvironment.)
82
89
  ```
83
90
 
84
- Set `ApplicationLabel` and `PropertiesFileName` at the node level in the flow:
85
- - `ApplicationLabel`: e.g., `BS_Account`
86
- - `PropertiesFileName`: e.g., `ACCOUNT-PROPERTIES.xml`
91
+ Typical node values (note the `${broker.name}` token):
92
+ - `PropertyFilename`: `${broker.name}/ACCOUNT.xml`
93
+ - `PropertiesGroup`: the property group, e.g. `BS_Account.GetAccountDetails`
94
+ - `LogicalTreePath`: leave as `Environment` (default) → properties land under `Environment.Properties`
95
+
96
+ It reads the file via the external `readerProperties(configFile, PropertiesGroup)` routine and builds
97
+ the tree under `LogicalTreePath`. `ApplicationLabel` is **not** a PropertyReader external — it is a
98
+ broker built-in correlation name (the application/library name), used when reading properties back.
87
99
 
88
100
  ---
89
101
 
@@ -8,19 +8,22 @@ The framework provides configurable retry for MQ-based flows using `RetryPoint.s
8
8
 
9
9
  | Component | Type | Purpose |
10
10
  |---|---|---|
11
- | `RetryPoint.subflow` | subflow | Re-queue message after failure with delay |
12
- | `SetRetryProperties.esql` | esql | Set retry tracking headers on MQRFH2 |
11
+ | `RetryPoint.subflow` | subflow | Re-queue message after failure with delay (runs `SetRetryProperties`) |
12
+ | `SetRetryProperties.esql` | esql | Seed the `MQRFH2.usr.retry` struct from `Retry` properties (or node externals) |
13
+ | `MQ_Input_Node_IsRetryEnabled.esql` | esql | FILTER: `Retry.RetryEnabled` (fallback EXTERNAL `RETRY_ENABLED`) |
13
14
 
14
15
  ---
15
16
 
16
17
  ## How It Works
17
18
 
18
- 1. On failure, message is caught by `ErrorHandler`
19
- 2. `ErrorHandler` checks `RetryEnabled` from Properties
20
- 3. If enabled, routes to `RetryPoint`
21
- 4. `SetRetryProperties.esql` increments retry count in `MQRFH2.usr.retry`
22
- 5. Message is re-queued to `MQRFH2.usr.sourceQueue` after `minWaitDurationSec`
23
- 6. When `maxRetryCount` is reached route to `MQ_Dead_Output_Node`
19
+ 1. On failure, the message is caught on the MQ input error path
20
+ 2. Retry is gated by `Retry.RetryEnabled` (filter `MQ_Input_Node_IsRetryEnabled`; fallback EXTERNAL `RETRY_ENABLED`)
21
+ 3. If enabled, routes to `RetryPoint`, which runs `SetRetryProperties`
22
+ 4. `SetRetryProperties` seeds the `MQRFH2.usr.retry` struct **only when not already present**:
23
+ `maxRetryCount`, `minWaitDurationSec`, and `sourceQueue` (= `InputRoot.MQMD.SourceQueue`).
24
+ The attempt counter is `MQRFH2.usr.retry.count` (read by `AuditPoint`)
25
+ 5. The message is re-queued to `MQRFH2.usr.retry.sourceQueue` after `minWaitDurationSec`
26
+ 6. When the attempt count reaches `maxRetryCount` → route to `MQ_Dead_Output_Node`
24
27
 
25
28
  ---
26
29
 
@@ -36,39 +39,41 @@ Under the `Retry` group for each flow:
36
39
  </group>
37
40
  ```
38
41
 
39
- | Property | Default | Description |
40
- |---|---|---|
41
- | `RetryEnabled` | `FALSE` | Enable/disable retry |
42
- | `maxRetryCount` | `5` | Max attempts before dead-lettering |
43
- | `minWaitDurationSec` | `60` | Seconds to wait before re-queue |
42
+ When the flow's `Retry` property group is present, values come from properties; otherwise
43
+ `SetRetryProperties` falls back to the node EXTERNAL defaults:
44
+
45
+ | Property (group `Retry`) | EXTERNAL fallback | Default | Description |
46
+ |---|---|---|---|
47
+ | `RetryEnabled` | `RETRY_ENABLED` | `FALSE` | Enable/disable retry |
48
+ | `maxRetryCount` | `MAX_RETRY_COUNT` | `0` | Max attempts before dead-lettering |
49
+ | `minWaitDurationSec` | `MIN_WAIT_TIME_SEC` | `60` | Seconds to wait before re-queue |
44
50
 
45
51
  ---
46
52
 
47
- ## MQRFH2 Headers Used
53
+ ## MQRFH2 retry struct
48
54
 
49
- | Header | Purpose |
55
+ `SetRetryProperties` writes a **struct** under `MQRFH2.usr.retry` (not a scalar):
56
+
57
+ | Field | Purpose |
50
58
  |---|---|
51
- | `MQRFH2.usr.retry` | Current retry attempt count |
52
- | `MQRFH2.usr.sourceQueue` | Original queue to re-queue to |
59
+ | `MQRFH2.usr.retry.count` | Current attempt count (read by `AuditPoint`) |
60
+ | `MQRFH2.usr.retry.maxRetryCount` | Max attempts for this message |
61
+ | `MQRFH2.usr.retry.minWaitDurationSec` | Delay before re-queue |
62
+ | `MQRFH2.usr.retry.sourceQueue` | Original queue (`MQMD.SourceQueue`) to re-queue to |
53
63
 
54
64
  ---
55
65
 
56
66
  ## ESQL for Retry Check
57
67
 
58
68
  ```esql
59
- -- Check current retry count
60
- DECLARE retryCount INT;
61
- SET retryCount = InputRoot.MQRFH2.usr.retry;
62
-
63
- -- Get max from properties
64
- DECLARE maxRetry INT;
65
- SET maxRetry = Environment.Properties.{AppLabel}.{flowName}.Retry.maxRetryCount;
69
+ -- Current attempt count and limit
70
+ DECLARE retryCount INT CAST(InputRoot.MQRFH2.usr.retry.count AS INT);
71
+ DECLARE maxRetry INT CAST(InputRoot.MQRFH2.usr.retry.maxRetryCount AS INT);
66
72
 
67
73
  IF retryCount >= maxRetry THEN
68
- -- route to dead letter
74
+ -- limit reached → route to MQ_Dead_Output_Node
69
75
  ELSE
70
- -- increment and re-queue
71
- SET OutputRoot.MQRFH2.usr.retry = retryCount + 1;
76
+ SET OutputRoot.MQRFH2.usr.retry.count = retryCount + 1; -- re-queue to .sourceQueue
72
77
  END IF;
73
78
  ```
74
79
 
@@ -7,13 +7,16 @@ All naming in this framework follows strict conventions. The agent MUST follow t
7
7
  ## ESQL Broker Schema
8
8
 
9
9
  ```esql
10
- BROKER SCHEMA Qiwa.<ApplicationName>
10
+ BROKER SCHEMA com.qiwa.esb.<msgflowname-lower>
11
11
  -- Examples:
12
- BROKER SCHEMA Qiwa.BS_Account
13
- BROKER SCHEMA Qiwa.BS_Transfer
14
- BROKER SCHEMA Qiwa.Framework.Lib ← shared lib only, never use for app code
12
+ BROKER SCHEMA com.qiwa.esb.getaccountdetails
13
+ BROKER SCHEMA com.qiwa.esb.createtransfer
14
+ BROKER SCHEMA Qiwa.Framework.Lib ← shared framework library only, never use for app code
15
15
  ```
16
16
 
17
+ The schema is the message-flow name, lowercased, with no separators. App ESQL must also
18
+ `PATH Qiwa.Framework.Lib;` to resolve the shared framework routines.
19
+
17
20
  ---
18
21
 
19
22
  ## ESQL Module Naming
@@ -174,7 +177,7 @@ Standard terminal names used in the framework:
174
177
 
175
178
  | Artifact | Format | Example |
176
179
  |---|---|---|
177
- | ESQL schema | `Qiwa.<AppName>` | `Qiwa.BS_Account` |
180
+ | ESQL schema | `com.qiwa.esb.<msgflowname-lower>` | `com.qiwa.esb.getaccountdetails` |
178
181
  | ESQL module | `<Flow>_<Purpose>.esql` | `GetAccountDetails_Compute.esql` |
179
182
  | Message flow | `<FlowName>.msgflow` | `GetAccountDetails.msgflow` |
180
183
  | Application | `<Tier>_<Domain>` | `BS_Account` |
@@ -27,8 +27,9 @@ Use ALL-CAPS domain name.
27
27
 
28
28
  <!--
29
29
  Group name format: {ApplicationLabel}.{FlowName}
30
- ApplicationLabel: set on PropertyReader node, e.g. "BS_MyService"
30
+ ApplicationLabel: the broker built-in application/library name, e.g. "BS_MyService"
31
31
  FlowName: the message flow name, e.g. "GetMyData"
32
+ This whole group name is what you pass as PropertiesGroup on the PropertyReader node.
32
33
  -->
33
34
  <group name="BS_MyService.GetMyData">
34
35