Handling Attachments During BPEL Process Execution
Introduction
ActiveBPEL version 4.0 adds support for interacting with attachments during execution of a BPEL Process. Attachments may be image files, a Word or PDF document, MP3 or WAV audio, a spreadsheet or a simple text file - any sort of unstructured data that can be sent along as an attachment to a WSDL web service request message.
ActiveBPEL provides a collection of custom functions to identify and manipulate attachments during process execution. This sample describes the basics.
The ActiveBPEL Designer User's Guide for Version 4.0+ (ActiveBPEL_User_Guide.pdf) discusses attachments in Chapter 11. If you haven't previously read this part of the documentation, please do so now. By default, the guide is installed in your ActiveBPEL Designer Docs directory:
[drive]:\Program Files\Active Endpoints\ActiveBPEL Designer\Docs
This sample assumes a basic familiarity with WSDL, WS-BPEL 2.0 (including use of correlation sets), ActiveBPEL Designer and ActiveBPEL Engine (or Enterprise), . Please be sure you are familiar with these topics before going on.
Objectives
- Examine a BPEL process that manipulates attachments using ActiveBPEL 4.0's custom attachment functions and file attachment support
- Use soapUI (or other attachment-aware Web Services development tool) to exercise the process
- Use the ActiveBPEL Admin Console to view / recover attachments in a running process
Getting Set Up
The files provided with this article are contained in Attachments.zip. You may extract this archive into a directory of your choosing. The archive contains numerous directories, and includes an ActiveBPEL® Designer project and various support, test and deployment files.
Because the custom attachment functions are specific to
ActiveBPEL, you should use ActiveBPEL Designer to create, simulate and
deploy your process. Start ActiveBPEL Designer and select File
/
Import. In the Import dialog, select General / Existing Projects
into Workspace and navigate to and import the following project directory
[path to extracted archive]/Attachments
This opens a project called Attachments,
which appears in the
Navigator View.
With the project successfully imported, you can now add the Web Reference file used by the process. This file is named attachmentAggregator.wsdl, and it's located in the support/wsdl folder of the Attachments project.
Switch to the Web References view and select the Add a Web Reference icon. Select the Browse Projects... button and navigate to the support/wsdl directory under Attachments. Add the attachmentAggregator.wsdl file. It appears in the Web References View and can now be used to define sample data, etc.
Collecting Attachments - an Insurance Industry Scenario
Medical insurance claims are often submitted to the insurance provider with attachments related to the claim. For instance, a testing lab might attach a scanned copy of the doctor's labwork order when submitting the test for reimbursement. Likewise, in rare cases a hospital might conceivably attach the entire scanned contents of a patient's medical history folder for an extended hospital stay that involves surgery, inpatient rehab, etc.
Clearing Houses are often employed to collect these health providers' insurance claims, and submit them for reimbursement. The claims are processed along with the associated x-rays, lab test results and any other paperwork from health care providers. Documentation is scanned, as needed, and the claim, along with the attached documentation, is electronically transmitted to the insurance provider. This transmission may involve multiple messages, in no particular order, each with zero-to-many attached (scanned) documents. It's not uncommon for an insurance provider to handle tens of thousands of such messages from multiple clearing houses each day.
For numerous reasons the insurance company must archive each claim, along with any associated attachments. To simplify this process, it is helpful to aggregate the incoming claim and documentation (attachments) before submitting the entire claim package, en masse, to an archival database.
The simplified use case for our sample BPEL Process involves aggregating all of the attachments for a each claim and - once they've all been received from the clearing house - submitting the entire package for archive. The system must be able to handle an arbitrary number of different claims simultaneously. Transmission of a new claim is begun by sending a message with a new claim number, along with one or more attachments. The number of messages required to send all subsequent attachments for a given claim is unknown, so a 'claim complete' message is sent in the form of a claim number message with no attachments.
In case of errors during the archive step, we don't want to lose any attachments received, so we also need a procedure to manually perform the archive step when necessary.
The Attachment Aggregator BPEL Process
Open the BPEL Process attachmentAggregator.bpel in ActiveBPEL Designer. It's located in the support/bpel folder of the Attachments project. Note that the process comprises two basic sections. The initial StartAggregation / Receive activity, followed by the LookForInitialAttachment_s_ / If activity comprise the process' initialization section. The CollectAdditionalAttachments / RepeatUntil activity handles ongoing aggregation of incoming attachments for the claim, archiving the package when all messages have been received.
Initial Message and Correlation by Claim Number
In our scenario, each incoming claim and all of its attachments will be handled by a single process instance. To do that we need to receive at least two messages into the same process instance - the initial message (with attachments) and the complete message (no attachments). We may also need to receive multiple messages for the same claim (i.e., the same process instance) in between. This requires correlation.
If you examine the properties for the StartAggregation activity (the initial Receive), you'll see that we initiate the values for the aggregation correlation set there. This ties the process instance to the claim number found in the first message (as the part named collectionID). Using correlation, subsequent messages with that same claim number will be routed to the GetNextAttachmentOrArchiveRequest / Receive activity by the BPEL engine.

After StartAggregation accepts the first message, LookForInitialAttachment_s_ checks to be sure that there are, in fact, one or more attachments included with the message. The If Condition's expression uses one of ActiveBPEL attachment functions:
abx:getAttachmentCount( 'attachments' ) > 0
This custom function returns the number of files attached to the message that was received into the (messageType) variable named attachments. If the number is greater than 0, then we can continue. If not, then the Else portion of the If activity is executed and the FaultResponse / Reply activity responds with a WSDL fault that includes a message containing the text "Attachment REQUIRED on initial request!" The process instance terminates at that point. This WSDL fault reply allows the Clearing House to automatically handle erroneous transmissions on their end.
If the number of attachments on the message is 1 or more, then we can assume that this is the first incoming message for this claim. In that case, the If Condition executes and a confirmation message issent to the Clearing House by the ConfirmStarted / Reply activity, indicating that we've received the attachment(s) and started aggregation for the claim number in the incoming message.
The actual aggregation of the initial attachment(s) is done using a different attachment function, which is used to copy the incoming attachment(s) to a variable - aggregation - that will hold references to the attachments throughout the life cycle of the process instance. So inside the SaveAttachment / Assign activity, we have the following from-spec:
abx:copyAllAttachments( 'attachments' , 'aggregation' )
and then a to-spec (Variable / tmp) which is really just a dummy variable to get the results of the call to the function, which we throw away. The function itself, contained in the from-spec actually does the necessary work here, copying any attachments from the message that was placed into variable attachments, to the variable named aggregation.
Important Note: when using the Expression Builder to create Copy Operations containing attachment functions, it's easy to accidentally select the variables from theVariables list, in which case you might have a function that looks like this:
abx:copyAllAttachments( $attachments, $aggregation )
This will usually fail validation, as the function arguments need to be variable name strings, not the actual variables themselves. Having said that, you can certainly pass in xsd:String variables to the attachment functions and dynamically control how attachments are moved, etc., but that is beyond the scope of this discussion.
Collecting the Rest of the Attachments
Now that the process instance has initiated handling of a specific claim number, we need to be able to accept any subsequent messages for that claim, collect up any more attachments and, finally, archive the package when we get a 'claim complete' message (i.e., one with the claim number but no attachments). We'll do this using the CollectAdditionalAttachments / RepeatUntil activity. This is an iteration activity that will keep reading in messages for a given claim until there are no more, at which point the process will set the condition that causes the activity to stop iterating.
The iteration loop comprises the following steps:
- GetNextAttachmentOrArchiveRequest waits for and accepts the next message for claim number Xxxxx
- SaveNextOrArchive checks the message for attachments -
- if none, that's the 'claim complete' message, so attempt to archive the package (PrepareForArchive, ArchiveAttachments), reply to the Clearing House with the final result (SendArchiveResult) and set the condition to stop the iteration (SetLoopControlToExit)
- if one or more, then continue aggregating (SaveAttachment) and confirm (ConfirmAdded)
- If an error occurs during archive, let the Scope's Fault Handler deal with it (SetFaultExplanation, FaultResponse and WaitForOperator)
Again, routing of the subsequent messages to the GetNextAttachmentOrArchiveRequest / Receive activity is handled by the BPEL engine itself, by virtue of the fact that this activity also uses (but does not initiate) the aggregation correlation set.
Both the SaveAttachment / Assign and PrepareForArchive / Assign activities use ActiveBPEL attachment functions to copy attachments from one variable to another. The from-spec in SaveAttachment is identical to the one we saw earlier in the claim processing initialization phase: it copies the attachments from the most recently received message to the aggregation variable, where they will be held until the archive step.
The from-spec in PrepareForArchive is subtly different - basically, it copies the attachments in the 'reverse' direction. The reason we can do this is that the archive operation is identical to the one exposed by our process. Therefore, it can accept the same message type, i.e., a single part containing a claim number. The archive service 'knows' that any attachments that come along with the message are associated with that claim. Knowing this, we can re-use the attachments variable in our ArchiveAttachments / Invoke activity. But first, in PrepareForArchive we copy all of the attachments to it from aggregator with a from-spec of:
abx:copyAllAttachments( 'aggregation', 'attachments' )
The attachments variable, which contains the claim number for this package, is then sent - along with all of the attachments we collected during the process instance's execution - to the archive service. The archive service's output variable - confirm - is also reused and sent back to the Clearing House by the SendArchiveResult / Reply activity. The condition is then set to exit the loop by SetLoopControlToExit.
Error Handling
Note that the NoAttachmentSoArchive / Scope activity contains a CatchAll fault handler. This handler will take over if any faults are thrown during the final phase of archiving the claim. For instance, the archive service may simply be unavailable (we're going to simulate this later with an actual running process). When this happens, it's important in our use case not to lose the attachments we've collected for the current claim.
What the fault handler does is send a WSDL fault reply to the Clearing House, indicating that there's a problem, and then the WaitForOperator / Suspend activity pauses the process
until someone can manually collect the attachments and archive them. In
our case this will be done via the ActiveBPEL Engine Admin Console.
Obviously, this is a rather simplistic error-handling scheme for a
high-volume claims processing system - a production design would, for
instance, check availability of the archive service before invoking -
but it suffices for our demonstration purposes.
Deploying the Aggregator Process
This sample provides a completed aggregator process, including a PDD and BPR file which are located in the support/deploy subfolder of the project. The BPR is ready to deploy to your running instance of ActiveBPEL Engine (or Enterprise). Simply copy the file into the bpr directory of your server. Alternately, if your BPEL engine is deployed to the default URL (i.e., http://localhost:8080/...) you can right-click on attachementAggregator.bprd in ActiveBPEL Designer's Navigator view and select Execute to deploy the process.
One item to note in the PDD before continuing, which is the endpoint reference definition for the partnerRole of the archiveAttachmentsPLT. This endpoint reference is set to invoke a local process named archiveProcess.
Unless you have a process deployed by that name, that process will not
actually exist. This is done purposely so that we can investigate the
error handling procedure when the archive invocation fails due to a
missing archive service.
Testing the Process with real Attachments
To test the attachment aggregator BPEL process, we'll need to send it some WSDL request messages with and without attachments. You may already have a tool you use to send WSDL / SOAP messages. If not, a handy one is soapUI, which is freely available for download here. The following instructions are based on soapUI version 1.7.1, but any higher version should work. Of course you'll need to modify these if you're using a different tool.
To begin, ensure that the attachmentAggregator process has been successfully deployed to a running instance of ActiveBPEL Engine (or Enterprise). Verify this by going to the ActiveBPEL Administration Console and examining the Deployed Services. You should see addAttachmentPLTService listed alongside a process name of attachmentAggregator.
Start soapUI by clicking on it's icon in the Windows Start / All Programs menu. When the Projects list appears, right click on Projects and select New WSDL Project. Enter a Project Name (e.g., Attachments). Task-switch back to the Admin Console and click addAttachmentPLTService in the list of Deployed Services. Copy the URL from your browser and then click its Back button. Task-switch back to soapUI and paste the URL into the Initial WSDL entry field. Check the box below this field and click OK.

Save the project configuration file to a convenient location. A new project appears in soapUI's Projects list. Fully expand this project until you see Attachments / addAttachmentPLTServiceBinding / add / Request 1. Double-click on Request 1 and the request construction window opens.

The request message has a single part: collectionID. This corresponds to the claim number for a collection of attachments. Replace the question mark with a string, e.g.,
Any message received with this ID will be treated by the process as part of the same archive package.
Next we need to add one or more attachments and enable attachment transmission. Select the Request Attachments (0) tab at the bottom of the request construction window. Click Add file and select a file of any type from your file system. Select Yes or No to cache (make a local copy of) the attachment, as desired - see soapUI's documentation for more info on this. Either will work for our purposes. Optionally, add more files as desired.
Once you've selected your attachments, enable attachment transmission by setting the Enable MTOM/Inline option to true. This is found on the Request Properties Details tab at the lower-left corner of the screen.
The request is now ready. Click the green 'Submit Request...' button at the top/right of the request window to send. A moment or two later, you should get a reply in the right-hand window similar to the following:
<soapenv:Body>
<added>true</added>
</soapenv:Body>
</soapenv:Envelope>
This indicates that the attachments were received and a new session has been started for the claim number provided.
A running instance of the process is now waiting for additional attachments or a 'claim complete' message. To verify this, go to the ActiveBPEL Admin Console and select Active Processes. The most recent instance of attachmentAggregator should appear at the top of the list, and its state should be Running. Click the ID or Name value to view the Active Process Details. When the details page appears, expand the variables section in the Outline View on the left and select aggregation. Below the process diagram on the right you can view the list of attachments currently being held for archive. Multiple attachments will appear as multipart/mixed, and may be difficult to view, but single attachments may be viewed or downloaded by clicking the Download link provided.

Note also that the process is currently running - the GetNextAttachmentOrArchiveRequest / Receive activity is executing, i.e., waiting for the next message to arrive. Send additional messages with attachments, as desired.
To complete the claim, we need to send a message with the same claim number, but with no attachments. Go back to soapUI and remove all attachments from the Request Attachments tab and, without changing the collectionID value, send the message again. You will receive a WSDL Fault message as a reply. This is because we have purposely set the archive service endpoint reference to a nonexistent process. Examine the reply message contents and you will find the following text:
Error detected during archive request - process Suspended. Operator Intervention Required!!!
This indicates something went wrong. Again, using the ActiveBPEL Admin Console, return to the Active Process Details for the running process instance. Refresh the page to see that the process instance is now in a state of Suspended. This is because our fault handler took over and the WaitForOperator / Suspend activity is now 'executing'. Check the diagram to verify this - the activity will be in the ReadyToExecute state.
Normally, at this point we would need to manually archive this particular set of attachments and eventually resubmit them once the error is corrected. To save the attachment files locally, right-click the Download link for each attachmentand select Save Target As... or Save Link As... (depending on your browser).
Feel free to experiment further with the process. For instance, you
can start up multiple instances by sending initial messages with
different claim numbers. View the individual process instance details
to view the list of attachments currently collected. An excellent
exercise - though beyond the scope of this discussion - would be to
create an actual archive service that will accept the attachments and
store them in your file system.
Copyright © 2004–2007 Active Endpoints, Inc.
