@@ -180,10 +180,53 @@ Conditional execution based on a field value.
180180 "switch": "/fieldName",
181181 "nodes": [
182182 {"type": "SEQUENCE", "label": "value1", "nodes": [/* steps */]},
183+ {"type": "SEQUENCE", "label": "$null", "nodes": [/* null handling */]},
183184 {"type": "SEQUENCE", "label": "$default", "nodes": [/* default steps */]}
184185 ]
185186}
186187```
188+ Special labels: `$null` (value is null), `$default` (fallback), blank (empty string match).
189+
190+ #### BRANCH with label expressions (expression-based branching)
191+ ```json
192+ {
193+ "type": "BRANCH",
194+ "label-expressions": "true",
195+ "nodes": [
196+ {"type": "SEQUENCE", "label": "code = 200", "nodes": [/* success */]},
197+ {"type": "SEQUENCE", "label": "code = 400", "nodes": [/* bad request */]},
198+ {"type": "SEQUENCE", "label": "name != null && status != null", "nodes": [/* both set */]},
199+ {"type": "SEQUENCE", "label": "$default", "nodes": [/* fallback */]}
200+ ]
201+ }
202+ ```
203+ Expressions support: `=`, `!=`, `null`, `$null`, `&&` (use `&&` in XML), `||`, regex (`/^pattern/`).
204+
205+ #### BRANCH with expression-guarded EXIT (conditional loop break)
206+ ```json
207+ {
208+ "type": "BRANCH", "label-expressions": "true",
209+ "nodes": [
210+ {"type": "EXIT", "label": "%count% >= %limit%", "from": "$loop", "signal": "SUCCESS"}
211+ ]
212+ }
213+ ```
214+
215+ ### REPEAT
216+ Retry/polling step. Re-executes children up to `count` times.
217+ ```json
218+ {
219+ "type": "REPEAT",
220+ "count": "3",
221+ "repeat-interval": "5",
222+ "repeat-on": "FAILURE",
223+ "nodes": [/* steps to retry */]
224+ }
225+ ```
226+ - `repeat-on`: `FAILURE` (retry on error) or `SUCCESS` (poll while succeeding)
227+ - `count`: max retries (`-1` = unlimited). Supports `%variable%` substitution.
228+ - `repeat-interval`: seconds between retries
229+ - `back-off`: multiplier for increasing delay between retries
187230
188231### SEQUENCE
189232Group steps with a label and exit condition.
@@ -193,6 +236,23 @@ Group steps with a label and exit condition.
193236
194237Exit-on values: `FAILURE` (stop on first failure, default), `SUCCESS` (stop on first success), `DONE` (run all regardless).
195238
239+ Optional `scope` attribute restricts pipeline visibility:
240+ ```json
241+ {"type": "SEQUENCE", "scope": "$myScope", "exit-on": "FAILURE", "nodes": [/* steps */]}
242+ ```
243+
244+ #### Try-alternatives pattern (SEQUENCE EXIT-ON="SUCCESS")
245+ Older alternative to FORM="TRY"/"CATCH". The outer SEQUENCE exits on first success — if the try block succeeds, skip catch:
246+ ```json
247+ {
248+ "type": "SEQUENCE", "exit-on": "SUCCESS",
249+ "nodes": [
250+ {"type": "SEQUENCE", "label": "try", "exit-on": "FAILURE", "nodes": [/* business logic */]},
251+ {"type": "INVOKE", "label": "catch", "service": "pub.flow:getLastError"}
252+ ]
253+ }
254+ ```
255+
196256### TRY/CATCH (CRITICAL for production services)
197257
198258TRY/CATCH is implemented using SEQUENCE elements with a `form` attribute. The TRY and CATCH are **sibling** elements (NOT nested).
@@ -962,6 +1022,150 @@ Clean pipeline keeping only specified variables:
9621022
9631023- `preserve` is a String array (field type `1;1`) listing variable names to keep
9641024- Everything else is removed from the pipeline
1025+
1026+ ## Example 16: REPEAT step (retry on failure with backoff)
1027+
1028+ Retry a service call up to 3 times with 5-second intervals:
1029+
1030+ ```json
1031+ {
1032+ "type": "REPEAT", "count": "3", "repeat-interval": "5", "repeat-on": "FAILURE",
1033+ "nodes": [
1034+ {"type": "INVOKE", "service": "mypkg.services:callExternalAPI", "validate-in": "$none", "validate-out": "$none"},
1035+ {"type": "BRANCH", "switch": "/responseCode", "nodes": [
1036+ {"type": "SEQUENCE", "label": "200", "exit-on": "FAILURE", "nodes": []},
1037+ {"type": "SEQUENCE", "label": "$default", "exit-on": "FAILURE", "nodes": [
1038+ {"type": "EXIT", "from": "$parent", "signal": "FAILURE", "failure-message": "API call failed with code %responseCode%"}
1039+ ]}
1040+ ]}
1041+ ]
1042+ }
1043+ ```
1044+
1045+ **REPEAT rules:**
1046+ - `repeat-on: "FAILURE"` = retry when a child fails (retry pattern for transient errors)
1047+ - `repeat-on: "SUCCESS"` = repeat while children succeed (polling pattern, e.g., JMS receive loop)
1048+ - `count`: max retries. `-1` = unlimited. Supports `%variable%` substitution.
1049+ - EXIT inside REPEAT with `from: "$loop"` breaks out of the retry loop
1050+
1051+ ## Example 17: LOOP with conditional limit (process at most N items)
1052+
1053+ Process items from an array but stop after a configurable limit:
1054+
1055+ ```json
1056+ {
1057+ "type": "LOOP", "in-array": "/files", "out-array": "/results",
1058+ "nodes": [
1059+ {"type": "BRANCH", "label-expressions": "true", "nodes": [
1060+ {"type": "EXIT", "label": "%processedCount% >= %limit%", "from": "$loop", "signal": "SUCCESS"}
1061+ ]},
1062+ {"type": "SEQUENCE", "exit-on": "FAILURE", "nodes": [
1063+ {"type": "INVOKE", "service": "mypkg.services:processFile", "validate-in": "$none", "validate-out": "$none"},
1064+ {"type": "MAP", "mode": "STANDALONE", "nodes": [
1065+ {"type": "MAPINVOKE", "service": "pub.math:addInts", "validate-in": "$none", "validate-out": "$none", "invoke-order": "0",
1066+ "nodes": [
1067+ {"type": "MAP", "mode": "INVOKEINPUT", "nodes": [
1068+ {"type": "MAPCOPY", "from": "/processedCount;1;0", "to": "/num1;1;0"},
1069+ {"type": "MAPSET", "field": "/num2;1;0", "overwrite": "true",
1070+ "d_enc": "XMLValues", "mapseti18n": "true",
1071+ "data": "<Values version=\"2.0\"><value name=\"xml\">1</value></Values>"}
1072+ ]},
1073+ {"type": "MAP", "mode": "INVOKEOUTPUT", "nodes": [
1074+ {"type": "MAPCOPY", "from": "/value;1;0", "to": "/processedCount;1;0"}
1075+ ]}
1076+ ]
1077+ }
1078+ ]}
1079+ ]}
1080+ ]
1081+ }
1082+ ```
1083+
1084+ **Pattern:** BRANCH with `label-expressions: "true"` at the top of the LOOP body acts as a guard. The EXIT label is evaluated as an expression — when it matches, the loop breaks.
1085+
1086+ ## Example 18: BRANCH with expression labels (multi-condition routing)
1087+
1088+ Route processing based on complex conditions:
1089+
1090+ ```json
1091+ {
1092+ "type": "BRANCH", "label-expressions": "true",
1093+ "nodes": [
1094+ {"type": "SEQUENCE", "label": "name != null && status != null", "exit-on": "FAILURE",
1095+ "comment": "both name and status provided",
1096+ "nodes": [{"type": "INVOKE", "service": "mypkg.services:searchByNameAndStatus"}]},
1097+ {"type": "SEQUENCE", "label": "name != null", "exit-on": "FAILURE",
1098+ "comment": "only name provided",
1099+ "nodes": [{"type": "INVOKE", "service": "mypkg.services:searchByName"}]},
1100+ {"type": "SEQUENCE", "label": "status != null", "exit-on": "FAILURE",
1101+ "comment": "only status provided",
1102+ "nodes": [{"type": "INVOKE", "service": "mypkg.services:searchByStatus"}]},
1103+ {"type": "SEQUENCE", "label": "$default", "exit-on": "FAILURE",
1104+ "nodes": [{"type": "INVOKE", "service": "mypkg.services:searchAll"}]}
1105+ ]
1106+ }
1107+ ```
1108+
1109+ **Expression syntax:** `= value`, `!= null`, `== $null`, `&&` (AND), `||` (OR), regex `/^pattern/`.
1110+ First matching expression wins. `$default` is the fallback.
1111+
1112+ ## Example 19: SOAP client call (WSD connector pattern)
1113+
1114+ Structure generated by IS when consuming a WSDL:
1115+
1116+ ```json
1117+ {
1118+ "type": "SEQUENCE", "exit-on": "FAILURE",
1119+ "nodes": [
1120+ {"type": "MAP", "mode": "STANDALONE", "comment": "set operation",
1121+ "nodes": [
1122+ {"type": "MAPSET", "field": "/wsdOperationName;1;0", "overwrite": "true",
1123+ "d_enc": "XMLValues", "mapseti18n": "true",
1124+ "data": "<Values version=\"2.0\"><value name=\"xml\">getCustomer</value></Values>"}
1125+ ]},
1126+ {"type": "MAP", "mode": "STANDALONE", "comment": "map request to SOAP body",
1127+ "nodes": [
1128+ {"type": "MAPCOPY", "from": "/request;4;0;mypkg.docTypes:getCustomerInput", "to": "/request;2;0/getCustomer;2;0"},
1129+ {"type": "MAPSET", "field": "/soapProtocol;1;0", "overwrite": "true",
1130+ "d_enc": "XMLValues", "mapseti18n": "true",
1131+ "data": "<Values version=\"2.0\"><value name=\"xml\">SOAP 1.1 Protocol</value></Values>"}
1132+ ]},
1133+ {"type": "INVOKE", "service": "pub.client:soapClient", "validate-in": "$none", "validate-out": "$none",
1134+ "nodes": [
1135+ {"type": "MAP", "mode": "INPUT", "nodes": [
1136+ {"type": "MAPSET", "field": "/method;2;0/localName;1;0", "overwrite": "true",
1137+ "d_enc": "XMLValues", "mapseti18n": "true",
1138+ "data": "<Values version=\"2.0\"><value name=\"xml\">getCustomer</value></Values>"}
1139+ ]}
1140+ ]},
1141+ {"type": "BRANCH", "switch": "/soapStatus", "comment": "check SOAP success/fault",
1142+ "nodes": [
1143+ {"type": "SEQUENCE", "label": "0", "exit-on": "FAILURE", "comment": "success",
1144+ "nodes": [
1145+ {"type": "MAP", "mode": "STANDALONE", "nodes": [
1146+ {"type": "MAPCOPY", "from": "/response;2;0/getCustomerResponse;2;0", "to": "/result;4;0;mypkg.docTypes:getCustomerOutput"},
1147+ {"type": "MAPDELETE", "field": "/response;2;0"},
1148+ {"type": "MAPDELETE", "field": "/soapStatus;1;0"}
1149+ ]}
1150+ ]},
1151+ {"type": "SEQUENCE", "label": "$default", "exit-on": "FAILURE", "comment": "SOAP fault",
1152+ "nodes": [
1153+ {"type": "MAP", "mode": "STANDALONE", "nodes": [
1154+ {"type": "MAPCOPY", "from": "/response;2;0/fault;2;0", "to": "/fault;2;0"},
1155+ {"type": "MAPDELETE", "field": "/response;2;0"}
1156+ ]}
1157+ ]}
1158+ ]}
1159+ ]
1160+ }
1161+ ```
1162+
1163+ **SOAP client pattern (from Tundra, IBM WxMCPServer):**
1164+ - `pub.client:soapClient` is the IS built-in SOAP invoker
1165+ - `soapStatus=0` means success, anything else is a SOAP fault
1166+ - Request: map typed doc -> `/request;2;0/operationName;2;0`
1167+ - Response: extract from `/response;2;0/operationNameResponse;2;0`
1168+ - Fault: extract from `/response;2;0/fault;2;0`
9651169"# ;
9661170
9671171const ADAPTER_SERVICE_REF : & str = r#"# Adapter Service Configuration Reference
@@ -1841,6 +2045,44 @@ Parses a JSON string into an IData document.
18412045
18422046---
18432047
2048+ ## pub.client (HTTP/SOAP/FTP Client Services)
2049+
2050+ ### pub.client:soapClient
2051+ Invokes a SOAP web service endpoint.
2052+ - **In:** `request` (Document - SOAP body), `method` (Document - `localName`, `nsURI`), `soapAction` (String), `address` (String, opt - endpoint URL), `soapProtocol` (String - "SOAP 1.1 Protocol" or "SOAP 1.2 Protocol"), `wsdBinderName` (String, opt)
2053+ - **Out:** `response` (Document - SOAP response body), `soapStatus` (String - "0"=success, "1"=fault), `header` (Document - HTTP headers)
2054+ - **Note:** `soapStatus=0` is success. Check via BRANCH on `/soapStatus`. Fault details in `/response/fault`.
2055+
2056+ ### pub.client:http
2057+ Sends an HTTP request (GET, POST, PUT, DELETE, etc.).
2058+ - **In:** `url` (String, req), `method` (String - GET/POST/PUT/DELETE), `data` (Object/String/InputStream), `headers` (Document), `auth` (Document - `type`, `user`, `pass`), `encodingType` (String)
2059+ - **Out:** `header` (Document), `body` (Object), `statusCode` (String), `statusMessage` (String)
2060+
2061+ ### pub.client.ftp:login
2062+ Opens FTP connection.
2063+ - **In:** `serverhost` (String), `serverport` (String, default "21"), `username` (String), `password` (String), `transfertype` (String - "ascii"/"binary"), `newSession` (String - "true"/"false"), `secure` (String - "true" for FTPS)
2064+ - **Out:** (session is stored internally)
2065+
2066+ ### pub.client.ftp:get
2067+ Downloads file via FTP.
2068+ - **In:** `remoteFile` (String - path on server), `localFile` (String, opt - local path)
2069+ - **Out:** `content` (InputStream if no localFile), `status` (String)
2070+
2071+ ### pub.client.ftp:put
2072+ Uploads file via FTP.
2073+ - **In:** `remoteFile` (String), `content` (InputStream/String/bytes), `mode` (String - "ascii"/"binary")
2074+ - **Out:** `status` (String)
2075+
2076+ ### pub.client.ftp:logout
2077+ Closes FTP session.
2078+ - **In:** (none)
2079+ - **Out:** (none)
2080+
2081+ ### pub.client.sftp:login / put / get / logout
2082+ Same pattern as FTP but for SFTP connections. Uses `serverAlias` or explicit credentials.
2083+
2084+ ---
2085+
18442086## Kafka / Streaming Integration
18452087
18462088### Kafka Listener Configuration
0 commit comments