With the advent of SAP NetWeaver Process Orchestration (SAP NetWeaver PO) it is possible to build stateful integration-centric processes solely based on Java technology. However, users who worked with the SAP NetWeaver Process Integration double-stack version (ABAP/Java) before cannot automatically migrate their existing ccBPM-based process models to SAP NetWeaver PO. Instead they have to remodel their processes to benefit from the features offered by SAP NetWeaver PO. Learn what to consider in order to bring existing ccBPM processes to the new environment. Some new techniques will help you in your own projects.
Key Concept
Modeling of loops using BPMN (Business Process Model and Notation) can significantly be simplified by making use of the multiple instance marker for activities and subprocesses. However, be aware of the consequences during runtime.
SAP NetWeaver Process Orchestration 7.31 (SAP NetWeaver PO) is SAP’s strategic future platform for all kinds of processes. It doesn’t matter whether you want to model human-centric or integration-centric processes; SAP NetWeaver PO is your one-stop shop to implement them. However, what do you do if you come from an SAP NetWeaver PI double-stack environment and you want to run the processes you have built before using ccBPM on SAP NetWeaver PO?
My previous article on this topic, “Bringing ccBPM-based Integration Processes to SAP NetWeaver PO: Why Automation Doesn’t Work” explained that a one-to-one translation of each individual ccBPM-process-shape to the new SAP NetWeaver Business Process Management environment (which is part of SAP NetWeaver PO and which is in the end responsible for executing stateful processes on the Java-stack) doesn’t make too much sense. The modeling languages being used by the different products (Business Process Execution Language [BPEL] in PI and Business Process Model and Notation [BPMN] in BPM) are conceptually too different to allow such an easy solution. I explained this by using an integration scenario which is shipped with every PI installation. It is a process for coordinating multiple flight bookings and is depicted in Figure 1.

Figure 1
ccBPM process for coordinating multiple flights
In just a few words the scenario works like this: A travel agency sends a document containing several flights for a customer. The flights are necessary for a journey the customer has planned. The task of the integration-centric process is to get all confirmations from the involved airlines whether seats for the scheduled flights are still available and let the airlines at the same time book a seat for the respective flight. If all flights can be confirmed and booked, the travel agency receives a success message. In case at least one airline cannot confirm a flight, any already-reserved seats for the other flights have to be cancelled and a failure message has to be sent back to the travel agency. In my other article I explained what an optimized BPMN-model for this problem looks like. This model is depicted in Figure 2.

Figure 2
Flight booking coordination using BPMN correctly
Obviously the process model is much leaner, easier to understand, and better to maintain than the BPEL-process shown in Figure 1. For a detailed explanation of why, see my previous article.
Unfortunately even this model, although correct BPMN, is not directly executable on SAP’s BPM-engine. The main reason is the receive step Receive Booking is inside the subprocess Booking Subprocess. In SAP NetWeaver BPM you can model a subprocess in two ways: either as a referenced or as an embedded subprocess. The embedded subprocess is directly positioned within the main process model as is shown in Figure 2. The advantage is that the subprocess can access process variables (defined as data objects) of the main process. This is indicated by the dotted arrow (referred to as an association) from the Update Confirmed List activity inside the subprocess to the Confirmed_List data object which is located in the main process model.
A referenced subprocess on the other hand doesn’t have this capability. It is modeled as a separate, completely independent process. Data between the main process and a referenced subprocess can only be exchanged via parameters. Why is this distinction between embedded and referenced subprocesses so important? Because in SAP NetWeaver BPM the reception of messages via an intermediate message event is only possible within referenced subprocesses, not embedded ones. Therefore, you have to create a dedicated new process that is later referenced as a subprocess from the main flight coordination process.
In addition, you have to consider that you don’t have access to the Confirmed_List data object from within the referenced subprocess. Therefore, the update of Confirmed_List has to be covered in the main process. Considering all these constraints, you end up in the process model depicted in Figure 3 representing the main process and the model depicted in Figure 4 representing the referenced subprocess.

Figure 3
Flight coordination main process

Figure 4
Subprocess for sending bookings to airlines and waiting for their replies
So how does this process work during runtime? You start with the main process shown in Figure 3. An incoming message contains customer information and the flights which make up the journey. An example incoming message might look like the one shown in Figure 5.

Figure 5
Incoming message
Obviously three consecutive flights provided by three distinct airlines have to be booked. This information is transferred via output mapping to the RequestedFlights data object. Next you are already reaching the referenced subprocess Send requests to airlines and receive status which actually points to the Airlines Booking Subprocess depicted in Figure 4.
Note
In SAP NetWeaver BPM you have to explicitly model two processes. You don’t have to maintain special settings to make a subprocess. A process automatically becomes a subprocess if it is referenced by another process.
Note the parallel multiple instance marker (
) at the bottom of the subprocess shape. It indicates the invocation of the subprocess as many times as there are flight entries in the RequestedFlights data object – three times in my example (the resemblance to the three lines of the parallel multiple instance marker is purely coincidental). Each individual flight is being passed to the subprocess as parameter. In order to make this happen you have to define a synchronous interface for the start event of the subprocesses. A suitable interface for my scenario looks like the one shown in Figure 6 (Input parameter) and Figure 7 (Output parameter).

Figure 6
Input parameter for the subprocess

Figure 7
Output parameter of the subprocess
A single flight request including customer details is handed over to the subprocess. The return structure of the output parameter contains the fields status and confirmed, which can both be used to identify whether the flight was either approved or rejected by the airline.
Equipped with this knowledge the behavior of the subprocess is fairly straightforward (compare Figure 4): the received flight is stored in the data object FlightRequest via output mapping of the start event. From there it is handed over via input mapping to the Send booking to airline step which simply forwards the message asynchronously to the Process Integration (PI) part of SAP NetWeaver PO. As it is an asynchronous operation, the process immediately proceeds downstream to the intermediate message event Wait 4 Reply. Here the process waits until an appropriate response message comes in via PI.
As a correlation condition for the intermediate message event I recommend you compare the flight data (customerNo, airline, from, to, date) of the FlightRequest data object with the incoming response data, which contains these fields as well. (Compare the data type FlightStatus_DT shown in Figure 7 that represents the incoming message). Only if all fields are identical will the correlation condition match.
Note that the fields customerNo and airline alone would not be sufficient to identify one process instance unambiguously as the journey could potentially consist of several flights served by the same airline. In such a case one incoming message would already release all the processes waiting for the same customerNo/airline combination leading to an incorrect behavior.
Once the message has arrived at the intermediate message event it is mapped to the FlightStatus data object which finally makes up the output parameter of the subprocess (via input mapping to the end event).
Remember that this subprocess is invoked in parallel for each flight entry in the RequestedFlights data object of the main process. For my example this means three parallel instances of the Airlines Bookings Subprocess resulting in the parallel activation of three correlation conditions for the intermediate message event. However, there are still some important questions unanswered:
- How do you make a subprocess to a multi-instance subprocess?
- How does the process know on which data it has to operate?
- How do you set the input parameters for the subprocess?
- How do you ensure that only confirmed flights are collected in the ConfirmedFlights data object?
Let’s walk through those questions one by one. I’ll begin with the question how to make a subprocess invocation to a multi-instance call. This is fairly straightforward. In the main process simply set the Parallel For Each radio button on the Looping tab of the subprocess shape (compare Figure 8).

Figure 8
Properties of the subprocess shape
Figure 8 shows the details of the Send requests to airlines and receive status subprocess step in Figure 3. By setting the Parallel For Each-radio button you also enable the Select collection radio button with an associated drop-down list. This drop-down list allows you now to pick the collection, which determines the number of invocations of the subprocess. In this case this is the flights collection that is part of the RequestedFlights data object. With that you know that the BPMN engine iterates over the selected collection and invokes the subprocess for each entry. What is left is the question of how the data is mapped to the input parameters of the subprocess. This secret will be revealed once you take a look at the Input Mapping tab of your subprocess shape (Figure 9).

Figure 9
Input mapping for the subprocess shape
What you see is the mapping from the process context (left side) to the input parameters of the subprocess (right side,) which is defined by the synchronous interface shown in Figure 5. Notice the node currentCollectionItem in the Process context area on the left. You didn’t define such a structure in your process context, so why is it showing up? This item was automatically created for you by selecting the collection during the definition of the looping conditions above. You need access to the individual items of your collection to pass them as input parameters to their respective subprocess instances. This automatically-created node does the job for you. It is only available on process steps with the Parallel For Each radio button set. As you can see in Figure 9, the flight values are mapped to their respective counterparts on the right side. This ensures the correct data provisioning for each of the instantiated subprocesses. Each subprocess works on its individual set of data.
Once the subprocess has finished you have to ensure the correct output mapping from the subprocess to the process context of the main process. Let’s have a look at the respective output mapping (Figure 10):

Figure 10
Output mapping for the subprocess shape
At first sight there seems to be nothing spectacular: the returned structure FlightStatus_MT is mapped to the respective flight lists of the ConfirmedFlights and StatusAllFlights data objects. However, there is much more going on behind the scenes.
First, you might be wondering how you can identify the return parameter of your subprocess in the process context on the left. If you take a closer look at the icons in front of each field you will recognize a slightly different icon for the returned structure (
) compared to the other process context variables (
). The gear wheel in the lower right corner in contrast to the dog-eared page makes the difference and indicates a return parameter.
Second, as I am mapping from a single element to a list, I have to make sure that each returned entry is appended to the lists. This can be achieved by right-clicking the mapping connection and choosing Assignment > Append from the context menu (Figure 11).

Figure 11
Appending an entry to a list
These settings are already sufficient to ensure the correct filling of the StatusAllFlights data object: all returned values are blindly appended to the flight list. However, the ConfirmedFlights data object is more demanding: only those flights should be appended for which either the confirmed field is set to true or for which the status field contains the string Confirmed. Obviously there is more to do than just attaching the entries. The solution for this problem can be found once you open the expression editor for the mapping to the flightStatusList node of the ConfirmedFlights process context variable (Figure 12).

Figure 12
Filtering entries
Obviously you apply a filtering function before the target field is mapped. The use of the filter function means that the value handed over to the function as the first parameter is only assigned to its target field in case the condition – formulated as string and representing the second input parameter of the filter function – evaluates to true. What does this mean in my example? The first parameter of the function represents the source structure that was returned by the subprocess. The second parameter represents the condition the function has to test and is represented as a String type. The substring to the left of the equals sign must represent a field of the FlightStatus_MT structure. In my example this is the status field (if you take a look at Figure 10 you can verify that status is indeed a field of the FlightStatus_MT field). Its contents are then compared against the value Confirmed. The function evaluates this condition via a string-comparison. Only if this condition is fulfilled is the value appended to the target list. As a consequence the ConfirmedFlights list contains only entries that have been confirmed by the airline. If you want to check against the confirmed-field, you just have to replace the condition string with “confirmed=true”.
Note
If you want to learn more about the filter-function (which can also be applied to a list instead of a single field as first parameter), I recommend the
online help.
Now that you understand how the invocation and the instantiation of parallel subprocess instances as well as the data flow between main process and subprocess work, I can explain the remaining steps with just a few words. After finishing all subprocess instances (and only in this case) the main process reaches the All Confirmed? gateway. For finding the right sequence flow to follow, the gateway compares the length of the ConfirmedFlights list with the length of the RequestedFlights list. The condition looks as follows:
numeric-equal(
count(ConfirmedFlights/flightStatusList),
count(RequestedFlights/flights))
Only if both lists contain the same number of entries can you be ensured that all requested flights have also been confirmed by the respective airlines and can send the success message via PI to the travel agency (the Yes path in Figure 3). Otherwise you send out Cancel messages to those airlines that confirmed their flights before.
Fortunately you can benefit again from the Parallel For Each behavior described above. This time I am applying the looping logic to a simple automated activity and not to a subprocess. The activity Send Cancel Msgs. To Airlines will be invoked as often as I have entries in the associated ConfirmedFlights data object.
Behind the scenes SAP NetWeaver BPM is not spawning so many threads in parallel. This would probably crash the system if you had hundreds or even thousands of list entries. Instead the calls are executed sequentially. This results in a longer execution time for this particular step as all calls have to be finalized before the next process step (Send Failure Message to Travel Agency in my example) is activated.
Note
More information about the Parallel For Each behavior can also be found in SAP Note 1676083. I highly recommend having at least version 7.31 SP04 of SAP NetWeaver Process Orchestration in order to run this scenario.
As the messages are being sent asynchronously to PI, the described scenario also works for higher numbers of list entries. The message is handed over to PI, doesn’t wait for a response, and can therefore immediately proceed with the next message. However, if you apply the Parallel For Each looping for synchronous service calls, you also have to consider the response time of the called back-end system. As it may take some time to respond, it can lead to significant delays until the whole loop is finished.
Remember the remark from my description above: only if all items have been processed by the step with the Multiple Instance marker does the process proceed downstream with the next activity. Take it into account if you want to apply the Parallel For Each looping in your own process models.
Once all Cancel messages have been sent out, your process can finish by sending a final failure message to the travel agency.
What’s still missing is the description of the PI integration flows that ensure the reliable communication between my integration process, the travel agency, and the airlines. For the sake of simplicity (and keeping this article to a reasonable length) the systems are all represented by files in the file system. Hence, the following integration flows (all covering asynchronous communication) are required:
- From the travel agency (File adapter) to the BPM process (SOAP adapter) sending the message containing the customer information and all requested flights
- From the BPM process (SOAP adapter) to the airlines (File adapter) handling the request message whether a seat can be reserved for a respective flight
- From each airline (File adapter) to the BPM process (SOAP adapter) covering the message transfer for the confirmation or rejection of the seat
- From the BPM process (SOAP adapter) to the travel agency (File adapter) transmitting the message containing the overall status of the journey
- From the BPM process (SOAP adapter) to the airlines (File adapter) taking care of the Cancel messages for the already confirmed flights
All integration flows look more or less the same. Figure 13 shows a typical example with the message transfer from the travel agency to the BPM process containing the customer information and the requested flights.

Figure 13
Integration flow from travel agency to integration process
On the left you can identify the sender and on the right the receiver component together with the interfaces they are sending or receiving. The arrows from the sender to the start event of the integration flow and from the end event to the receiver (also known as message flows in BPMN nomenclature) show you the used adapters (File and SOAP adapter respectively). Obviously no further message handling (such as receiver determination, interface split, or mapping) is necessary and the message is being forwarded without changes to the receiver.
Only the messages from the integration process to the respective airlines (e.g., for the seat request or the cancelation) require a content-based routing step as is shown in Figure 14.

Figure 14
Integration flow from the integration process to the airlines
Based on the contents of the message it is forwarded to one of the airlines. The airline field is evaluated for this decision. The associated configuration of the Recipient List element in Figure 14 is shown in Figure 15.

Figure 15
Defining the conditions for the content-based routing
The settings of the SOAP-adapter for connecting the integration-centric process with PI has been explained in great detail in my article, “Benefit from the Tight Integration Between SAP NetWeaver BPM and AEX Without Configuration,” enabling you to rebuild the scenario on your own environment.
This concludes my article about the remodeling of a more sophisticated ccBPM scenario using SAP NetWeaver BPM which takes over the stateful integration processes within the new SAP NetWeaver Process Orchestration package. You have learned how to remodel typical ccBPM situations and constructs by applying the appropriate BPMN elements. You are now equipped to start your own migration projects.
One final remark: due to the use of the Parallel For Each loop you might challenge SAP’s BPM engine if it comes to messages containing many (hundreds or thousands) of entries. You may ask yourself whether there is an alternative approach which would relief the BPM engine from this burden. The answer is “yes” but explaining the alternative is worth another article.
Note
I’d like to thank my colleague Christian Loos for his constructive feedback on this article.

Dr. Volker Stiehl
Prof. Dr. Volker Stiehl studied computer science at the Friedrich-Alexander-University of Erlangen-Nuremberg. After 12 years as a developer and senior system architect at Siemens, he joined SAP in 2004. As chief product expert, Volker was responsible for the success of the products SAP Process Orchestration, SAP Process Integration, and SAP HANA Cloud Integration (now SAP HANA Cloud Platform, integration service). He left SAP in 2016 and accepted a position as professor at the Ingolstadt Technical University of Applied Sciences where he is currently teaching business information systems. In September 2011, Volker received his Ph.D. degree from the University of Technology Darmstadt. His thesis was on the systematic design and implementation of applications using BPMN. Volker is also the author of Process-Driven Applications with BPMN as well as the co-author of SAP HANA Cloud Integration and a regular speaker at various national and international conferences.
You may contact the author at editor@SAPpro.com.
If you have comments about this article or publication, or would like to submit an article idea, please contact the editor.