I just finished my first Mule flow. My flow receives an Alfresco node reference and declares a corresponding record in the Alfresco Records Management Application. I learned about Mule and Alfresco RM along the way… specifically, I learned to think like a Mule, instead of a Java developer.
Take the sub-flow to create the record folder. This folder may or may not already exist. In a concurrent environment, I prefer to try creating the folder first; if that fails, then lookup the folder by path. Either way, the sub-flow has to find the folder node-reference so I can later file the new record into the folder.
The try/catch approach. In a Java class, I might implement this by catching the exception from the create attempt. So in my Mule flow, I tried adding an error strategy. Many things went wrong with this. My custom error strategy had to apply only the record folder lookup flow, so it has to be defined in that flow (otherwise it would handle any other unrelated errors that might occur during the overall records management flow). But Mule only allows custom error strategies in flows… not in subflows. Later I found out calling a private flow changes flow variable visibility: this caused me many problems until I realized what was happening. Also, Mule didn’t always call my error strategy when record folder creation failed; also, it still propagated the error to the outer flow, which tended to stop all processing. In short, this approach failed completely!
The first-successful approach. Mule’s first-successful message processor seemed like just the ticket. And it was a real Mule approach – not Java encoded in Mule! I add a first-successful element with two internal processes: the first one to create the folder, the second one to lookup the folder ID. If the first one failed, Mule will automatically try the second one, and all will be well!
<first-successful> <enricher doc:name="create-record-folder"> <!-- .... --> </enricher> <enricher doc:name="get record folder id"> <!-- .... --> </enricher> </first-successful>
Well, this didn’t always work either, most likely because I didn’t know how to tell Mule how to distinguish success from failure.
The keep trying approach. Since the first-successful approach sometimes worked, I thought to myself, well, let’s just keep retrying it!
<until-successful objectStore-ref="until-successful-object-store" maxRetries="15" secondsBetweenRetries="1"> <first-successful> <enricher doc:name="create-record-folder"> <!-- .... --> </enricher> <enricher doc:name="get record folder id"> <!-- .... --> </enricher> </first-successful> </until-successful>
The less said about this, the better. If it didn’t work the first time, I just saw 14 more failures in the log. Very depressing!
The check-the-result-code approach: it works! Checking the result code is older than Mule obviously; older than Java; older than structured exception handling! But it works very well in this situation.
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="create record folder" encoding="UTF-8" ref="alfresco-create-record-folder" contentType="application/json; charset=UTF-8" mimeType="application/json"> <response> <json:json-to-object-transformer name="getJsonFromRecordFolder" returnClass="java.util.Map"/> </response> </http:outbound-endpoint> <choice doc:name="Choice"> <when expression="message.inboundProperties['http.status'] == '200'"> <set-variable variableName="record-folder-id" value="#[message.payload.persistedObject]" doc:name="Variable"/> </when> <otherwise> <processor-chain doc:name="Folder Lookup"> <!-- lookup the folder here.... --> </processor-chain> </otherwise> </choice>
If we get an HTTP 200 response to the first try, then we did create the folder, so we just record the new folder ID from the response JSON. If we did not get an HTTP 200, we assume the folder already existed (which is a good enough strategy for my purposes at the moment), so we lookup the existing folder’s ID.
Writing this first Mule flow definitely has had the desired educational effect. I feel I have a good basic understanding of the Mule platform now. Also, when I run into roadblocks or undesired / inexplicable behavior, now I will trust the defect is in my understanding, and not in Mule itself. At least for such basic use cases as this one!