BPEL – Business Process Execution Language
When the Web Services standard was being baked and shortly after its early adoption, the hopes for it were extremely high. Businesses looked to create reusable services across their enterprise. All looked good. As the services started to appear, applications were then written to build solutions from these by writing code that called the services when needed. As time passed, more and more services were built and patterns started to appear in the methodology of how solutions were built. Common discussions went along the lines of "First we call Service A, then we call Service B and depending on the outcome, we call Service C or Service D". In effect what we were seeing was the creation of the desire to aggregate services together to flesh out the solutions. The path taken to call the services tended to be linear with decision points along the way. Naturally this could be coded up in Java or another programming language, but this required coders, skills and it was not readily apparent by looking at the code just what was going on.
From this state of affairs, an idea was born. What if we could provide a descriptive language that was oriented towards invoking services in sequence? This language would accommodate calling services, would have variables and would provide decision points where different paths could be followed based on the values of variables and previous service calls. This was the beginnings of the language called Business Process Execution Language (BPEL).
At its most basic level, BPEL is an XML document that conforms to the BPEL prescribed XML Schema. The tags in the document have precise semantics associated with them. For example, a tag called <Invoke> causes a service to be called. By describing the sequence of steps to be executed in BPEL and by having a runtime engine that can understand BPEL, we effectively have a control language for invoking services in sequence. Effectively, we have created a "flowchart" like language (that goes back to the 1970s).
BPEL became an industry standard championed by OASIS and supported by many vendors. IBM brought a product to market that was called WebSphere Process Server (WPS) that acted as a BPEL runtime engine. That BPEL engine is what is now found in IBM Business Process Manager Advanced.
A BPEL process description could be written with a text editor if one knew the XML syntax for the language … however … that would be error prone and would basically have the similar maintenance and readability issues as was previously found by writing solutions in application code. IBM solved this problem by providing a sophisticated BPEL editor. This editor allows the user to build BPEL solutions visually. A canvas areas is shown and into that canvas, the various BPEL activity types can be dragged and dropped from a palette. The activities can then be visually wired together to describe the control flows. The end result is a flowchart style diagram which is actually a visual representation of the underlying BPEL. This BPEL editor is now a core part of the IBM Integration Developer IDE used with IBM Business Process Manager Advanced.
With this brief background on BPEL, the remainder of this section will drill down into the BPEL language and how it can be utilized with IBPM.
When one learns a new programming language (say Java for instance), you would be taught the basic constructs of the language. This would include variable definitions, assignments, loop syntax, function calling and others. Once you have and understanding of the grammar and can then make sense of a single line of code when you see it, only then can you start to go further and put together multiple lines of code to build a program. I am going to treat our learning and understanding of BPEL in the same way. First we will examine all the separate building blocks of a BPEL program and, once we are comfortable with those, then we can turn our attention to building complete solutions. First, we will look at the nature of a BPEL Process.
The notion of a BPEL Process
Notice that the "P" in BPEL stands for "Process" and the "B" in BPEL stands for "Business". Arguably, BPEL was an early beginning to the BPM story. It was definitely a start in making the IT solutions that run a business much more comprehensible to the business process workers in such a company. But … it could never have been written by business oriented staff. BPEL is quite definitely in the domain of needing IT skills to build and maintain. BPEL pre-dates BPMN (which was originally just a drawing language) and the hope was that it would bring business process owners and IT staff responsible for creating such processes much closer together. To some degree, that did indeed happen however because of the IT nature of BPEL, there was never truly a daily pollination between these two camps.
So where does that leave BPEL today? My opinion is that BPEL is still extremely relevant for the central core of what it was designed to do … namely to invoke multiple external services in a specific order. Whether those services are business related (debit one account, credit a second account) or IT related (Add a row to the DB2 database, place a message on an MQ queue), the tactic is still the same. BPEL is IT centric while BPMN is business centric.
However one wishes to perceive BPEL, knowing what it is and what it isn't is extremely important to understanding all of IBPM. Part of understanding BPEL is to understand its history and some of its language and that brings us back to "Process". In BPEL, the most coarse grained entity we can build is called a "Process". Going back to our flowchart analogy, the process can be thought of as the flowchart as a whole. Before we can create BPEL activities to describe what we want to achieve, we must first create the process.
Variables in BPEL
When we think of an Java application, we can think of it as a combination of control statements and variables. As the application runs, it executes sequences of statements that update and use the values of variables within the program. At any point in time, the state of the program is characterized by where we currently are in terms of the next Java statement to execute plus the values of the variables in effect. BPEL is not that different. Just like programming, BPEL has the notion of variables. A variable is a named entity within the process that has an associated data type. As the process executes a sequence of BPEL activities, these activities can retrieve or update the values of these defined variables. The data types of the variables can be any of the simple data types such as string or integer but they can also be types as Business Objects allowing a variable to represent a complex structure.
When a BPEL process template is created, that does not mean that there are now running instances of that process. Somehow instances of the BPEL processes has to be brought into existence. This is where the BPEL Receive activity comes into play. The Receive activity is commonly found at the start of a BPEL process template. Its purpose is to flag the starting point of the process. Associated with the Receive is an Interface and operation. The Interface is what the BPEL process exposes to the outside world to allow it to be invoked. If a caller invokes an operation on the interface, it is the Receive activity within the process that is given control.
When we think of an Interface and operations on that interface we should recognize that an operation can have input parameters. When we define a Receive activity we must also define BPEL variables that will be used to hold copies of the passed in parameters. When an external caller invokes the BPEL process, any parameters supplied by the caller can then be found in the variables within the process by subsequent activities following the Receive.
In the following diagram, we illustrate this idea in more detail. A caller invokes the exposed interface to the process and passes in parameters p1 and p2. The Receive activity is configured to be associated with the interface and operation and also to map the incoming parameters to local variables (v1 and v2). Following the completion of the Receive activity, control passes onwards to the next activity in the flow.
The Reply activity is closely related to the Receive activity. When a Reply activity is encountered in a process it sends a response back to a caller that previously caused a Receive activity to be executed. Similar to the Receive activity, the Reply activity maps variables to the expected response parameters of the call. When the Reply is reached, the values of the variables in effect at that time are used as the response values to the caller. Typically, processes conclude with a Reply activity but it is important to note that Reply does not indicate the end of the process. If there are additional activities following the Reply, these will be executed as normal. Only one reply can be sent to a previous caller.
In the following diagram, we illustrate the use of the Reply activity. When Reply is reached, it is associated with the interface and operation that had a previous Receive. In addition, the values of the variables v1 and v2 and used to build the response values to the caller of r1 and r2. Note that the variables used for reply don't have to be the same variables used in the Receive.
The Invoke activity is arguably the heart of the BPEL language. Its purpose is to call outbound to a service that lives outside the process and wait for a response. When the Invoke activity is added to the process diagram, it must name an interface and operation that it wishes to call. In the likely event that the operation has input parameters, the Invoke activity names BPEL variables who's values will be used and passed to the partner when the call is made. For return parameters from the Invoke, these are also mapped to BPEL variables.
In a BPEL process there are variables. The values of these variables may have been set by input data when the process was started or set by returns from Invoke activities. It is not uncommon for us to want to set or change the values of these variables while the process is executing as part of the process. For example, an Invoke activity may call a service that calculates the cost of a customer's order while a second Invoke calculates the shipping cost. The result may need to be a total cost and hence we must update a variable used for the Reply with the sum of the two previous values.
When added to the BPEL process, the assign activity allows us to specify expressions using the XPath language. We can assign values to the variables from either constant values or expression based on the values of other variables.
The Wait activity causes the process to suspend its own execution for a period of time. The amount of time can be described as either a relative value from when it is executed or a specific date and time in the future.
The Choice activity is a decision point mechanism within the process. When reached, a series of XPath based expressions are executed. The first of these expressions that evaluates to true then causes activities beneath that expression it to be executed. Associated with the Choice are one or more such expressions that are called "cases".
While Loop Activity
The While Loop activity executes its child activities while a boolean expression associated with the loop remains true. It is assumed that the activities will cause the expressions outcome to eventually change by updating some variable's value where the expression uses that variable.
Repeat Until Loop Activity
Similar to the While Loop, the Repeat Until Loop executes its child activities until some condition becomes false. Since the expression is evaluated after each iteration of the loop, the body will be assured to be executed at least once.
For Each Loop Activity
The For Each Loop activity executes its body some defined number of times. This can be a fixed loop or can be based on the number of elements in an array. The For Each Loop had a variety of additional options that can be used to control its operation.
Parallel Activities Activity
The Parallel Activities activity is a container for other activities. When reached, it causes all the activities contained within to start executing concurrently with each other. The Parallel Activities container does not terminate until all of the contained activities have themselves terminated.
The Scope Activity is another container activity. When reached, it provides a new and nested environment in which its contained activities execute. Think of it as providing a "scope of control". Amongst its functions it includes the ability to define BPEL variables that are local in scope only to the Scope Activity. When the Scope Activity completes, any variables associated with that activity are deleted. In addition to variables other BPEL constructs can also be associated with the Scope such as fault handler for handling errors, event handlers for handling out of band events and compensation handlers for handling transactional characteristics.
Generalized Flow Activity
Normally when activities are added to a BPEL process, one activity explicitly follows another. There is no actual visual wiring that need be done as inserting an activity after or between two existing activities implicitly declares where it will be executed in the sequence of work. On occasion, we may wish much finer grained control and choose to explicitly wire one activity to another. It is here where the Generalized Flow Activity comes into play. Activities contained within this container must be explicitly wired together to describe their order of execution.
The Terminate Activity causes the instance of the process to come to an immediate conclusion. This activity is implicitly present as the last activity in a process and hence need not be explicitly included. When reached, the process simply and cleanly ends. The Terminate Activity is not an error indication.
The Throw Activity results in an error condition being indicated. It is similar to the Java Language throw construct. How the caught error is handled is dependent on whether or not there are event handlers in place.
In-line Human Task Activity
This activity is not currently part of the BPEL specification but is instead an IBM addition. When reached, it causes the BPEL process to suspend and a new work item to be created for human attention. The work item is created in the Human Task Manager engine which is distinct from the Human Task manager functions found in the BPMN engine.
The Snippet Activity is another IBM extension to the BPEL specification. The Snippet Activity allows us to supply in-line Java Code that will be executed within the context of the process when it is reached. The activity has access to all the variables in the process both for read and write. By escaping down into Java code, virtually any algorthimics that need be performed can be achieved.
Transaction processing is the notion that when a program or process runs, its outcome should be "all or nothing" and not some indeterminate state. Consider for example a process that transfers funds from one bank account to another. A simple implementation may first debit one account and then immediately credit another. But what if there is a failure (such as a power outage) following the debit but before the credit? The first account will have had funds reduced while the second will not have had the funds added. We can not simply re-execute the process because this would result in two debits to the first account and again we will be in trouble.
What is needed is the ability to react to a failure by undoing the work that was previously done so that the process can behave as though it had never started in the first place. If it had never started, then we would be safe to restart after a failure.
The classic IT solution to this problem is to use a paradigm called two-phase commit. In this story when an update is made to some data by a process, the data owning system knows that it is part of a recoverable transaction. A good example of such a data owning system would be a database. When data is changed, added or removed, it is not really changed. It is held in a pending state until either the transaction as a whole commits (completes successfully) or rolls back (indicates a failure). In the event of a commit, the changes are made permanent and can no longer be undone. For a roll back, the data owning system has the ability to undo any changes made as part of that transaction. At the conclusion of the roll-back, the data is returned to the state it was in prior to the transaction having started.
Two-phase commit has been around for a long while and is implemented as part of the WAS server. Updates to recoverable resources include databases, JMS, and Java EE resources such as EJBs. Unfortunately, there are some limitations to two-phase commit. In order for it work, all the participants in the transaction that can own or change data must be able to know that they are part of a transaction. This is commonly achieved through an industry standard transaction processing protocol called "XA". Typically, Web Service calls do not participate in transactions. Web Services have always been considered stateless. What this means is that when a Web Service call is made to a Web Service provider, upon conclusion of the provider processing the request, it forgets everything about the previous call and passively waits for the next one to arrive. A key concept of two-phase commit is that the data owning system remember previous interactions and be informed about the final outcome of the transaction. A second problem is that transactional updates to data owning systems must be of short duration. Imagine if this were not the case. Consider debiting an account by $100 and then not concluding the transaction for a long period of time. During this period another program or system may come along and ask for the value in the account. To return a value that is $100 less than when the original process started would probably be a mistake as there is an opportunity that the monies will be returned if the transaction is rolled back. What commonly happens in these instances is that other users of the data are suspended until the transaction concludes one way or another. If a transaction takes a long time to complete (say many minutes or hours), the system can quickly grind to a halt and worse, deadlock scenarios can be introduced.
For both the preceding reasons, the BPEL standard does not support the two-phase commit protocol. This would seem to imply that BPEL can't support transactions. Fortunately, BPEL has come up with a solution. That solution is called compensation.
If we think back to the primary goal of transactionality which is to return the state of a system back to its original state that existed before the process started, in the event of a failure, we can perform an explicit undo operation to undo what was previously done. Back to our funds transfer example. If we debit an account by $100 and then fail to credit a second account, if we perform a credit of $100 to the original account, the end result will be that the original account is back to its starting value. We say that the original debit has been compensated. Compensation is the act of performing a secondary operation that reverses the first operation.
Within BPEL we can define what are called Compensation Handlers. A Compensation Handler is a set of additional BPEL activities that can be associated with other BPEL activities. In the event that a failure is detected, BPEL can automatically cause the Compensation Handlers to be executed. Each Compensation Handler would this be responsible for undoing what was done previously.
BPEL and AIS
When we create an AIS we are saying that when called it will invoke an SCA module. Within that module we can have a BPEL process. This means that we can invoke a BPEL process from an AIS. There are some very interesting effects that we can achieve with this combination.
BPMN compensations using BPEL
One of the more interesting abilities is the idea of using BPEL compensations to undo the effect of a BPMN described process. To illustrate this, I will keep the story generic to explain the principles which can be applied to an arbitrary process solution. Let us start by examining a simple BPMN process as follows:
In this story, we see that the process is composed of three steps each executed one after another. We will assume that these steps also update external data systems (systems of record). Since the process updates external systems, if we were to terminate or cancel the process, we may very well be left with an inconsistent data environment. For example, if a step scheduled someones time for some future work and the process was canceled, that person may still have the booked time on their calendar even though there is now no need for them to do any work. Another example would be allocating parts in a warehouse for assembly which is now no longer going to happen. Those parts would be considered "reserved" and would incorrectly not be able to be used for other projects.
What we need to do is "undo" the steps that were previously executed to return the environment to a logically consistent and accurate state. One way to achieve this is to explicitly model it within our process. An example might be:
Hopefully you can see how this would work but it also starts to get awkward very quickly. Another possibility for modeling would be to use the "Event Sub-process" notion:
Here the "Undo" step is executed in the event of an exception. The implementation of that might look like:
This looks a little better but now we have to explicitly track which steps in the process were actually performed so that we can know which ones to undo. In addition, the story starts to break down if we have branches or loops in the original process.
Ideally what we would like is the notion that the steps performed by the process which update external systems are somehow "tracked" by the BPM run-time. Since BPM would then "know" which steps were previously performed, BPM would then be able to automatically execute the undo steps to rollback or "compensate" what the process had done so far before it was canceled.
Fortunately, we can achieve exactly this capability by leveraging the compensation architecture of BPEL. When a BPEL process executes a step, BPEL remembers that it has executed that step. In addition, we can instruct BPEL on what to do "if" that step was ever asked to be undone. Since BPEL now knows what steps were actually performed and what to do if the step is to be compensated, BPEL can now automatically go through its history of steps performed and execute the compensation steps to undo those.
This is a great notion, but we want to avoid writing our business processes in BPEL but instead use the power of BPMN and its business level comprehensibility to model. How then can we merge the story to achieve the best of both worlds?
With IBM BPM Advanced, we have the ability to define steps as being executed by an "Advanced Integration Service" or AIS. When an AIS is reached in IBM BPM, this is an instruction that the work is to be performed by an SCA module and an entry into the SCA module is achieved. Within the SCA module, we can create a BPEL process and wire the AIS call as an entry into that BPEL process. Putting this in simpler terms, we can have an AIS call within BPMN be a call into a BPEL process.
What we can then picture in our minds is something along the following lines:
What this picture represents is the notion that the BPMN process does not make the changes to the external data systems. Instead, BPMN uses AIS to ask BPEL to make the changes. Since BPEL is making the changes, BPEL knows which steps were performed and how to undo those in the event of a failure.
So far so good, so let us start taking this notion to the next set of steps with the goal of actually achieving this design. The first thing to realize is that when the BPMN process runs we can logically think of it as being a process that runs for some period of time until it has a final outcome. Similarly, we need a corresponding BPEL process to also exist for the same duration. The BPMN process and the BPEL process are distinct from each other. There is no known technique that will cause the BPEL process to complete simply because the BPMN process completes. This means that we have to introduce a signaling mechanism that is executed at the very end of the the BPMN process to say that the process has completed and that the corresponding BPEL process can also complete. It is important that we do tell BPEL that it is complete so that it no longer has to maintain the knowledge of how to undo previous steps. If we failed to do this, BPEL would have to remember how to undo previous steps that are no longer ever going to be asked to be undone. We would have a resource leak that would hurt us.
The second thing to consider is that if the BPMN process is asked to undo, we need to tell the BPEL process that it too has to undo its previous work. This introduces a second signal that should be sent from the BPMN process that asks BPEL to rollback. Putting these together we are saying that the BPMN process must either tell BPEL that we are complete or that we are to compensate. One of these must be performed before the BPMN process can be forgotten.
We will call these two types of signals
Given that there may be many instances of the BPMN process in existence, it is important that we direct requests to the corresponding correct instance of the BPEL process. This is achieved through the concept of "correlation" which is a first class entity in the BPEL world. In order to achieve correlation, it is suggested that we use the Process Instance ID of the BPMN process as the correlation key.
The signature of the two signals then becomes:
Looking back at the implementation of the data updates that the BPMN process wishes to perform, we saw that each of these will be modeled in BPMN as AIS services. We now also see that these AIS calls will also need the correlation ID so that all work is performed within the same BPEL process instance.
Hopefully we now see all the pieces that we need to provide in the BPMN side of the house to achieve our model and now we turn our attention to the details of the BPEL story.
We see that in Process Designer, we have the following AIS definitions.
When we open the project in IID, we see the same items:
Next we implement these choosing "Empty implementation". At the end of this, we now have entry points for each of the AIS's:
Before we go any further, let us look at a generated interface for one of these AISs:
Notice that the operation name generated is "invoke". This is the same operation name for each of the services. We will run into problems if all our operations have the same name as the BPEL interface built for us won't be able to distinguish one operation from another. What we now should do is rename the operation names in each of the generated interfaces. This is an easy task and a good name for the operation is the same name as the service as there will only ever be one operation per service.
With this done, we can create a new BPEL process and wire each of the SCA entries into the process. The result will be:
The way to interpret this is that each AIS call will now result in an entry into the BPEL Process.
Now comes the fun part. Now we have to implement the BPEL process to achieve all of these steps. One possible solution looks as follows and is extensible to a wide variety of situations:
To fully comprehend the elegance of this solution, one really has to have an understanding of BPEL. What follows is a summary description.
The core of the solution is a "while loop" which simply loops forever. Within the while loop is the BPEL "Receive Choice" activity. This suspends the process until such time as one of the interfaces to the process is called. The Receive Choice will be waiting for any and all of the different types of interface in our story. Through the magic of BPEL, there won't actually be an instance of this process in existence before the first call from BPMN. The Receive Choice is flagged to create a new process if none already exist. This causes the BPEL run-time to listen as though there was a process but no actual process is present. When the first call arrives for which there is no corresponding correlation ID, a new instance will be created. For all subsequent calls with the same correlation ID, the requests will be directed to the already existing instance for processing.
The "function" steps (Step A, Step B and Step C in this example) have a BPEL "Scope" attached to them. Within this Scope we perform the logic necessary to achieve the required request. This could be a database update, a Web Service call, a messaging call or a wide variety of other possibilities. Associated with each BPEL Scope is a compensation handler. This is the logic that will be invoked to "compensate" for the work done in the body of the scope should compensation be needed. It is this logic plus the associated data that the BPEL run-time remembers should it need to subsequently perform compensation. The logic to actually perform the compensation is itself defined in the compensation handler and can again be any of the back-end integrations that may be needed. Remember also that the data needed to perform the compensation is also part of the compensation scope and hence quite subtle and sophisticated permutations are handled automatically for us.
The logic of "BPEL Commit" is merely to terminate (gracefully and normally) the BPEL process. This causes the run-time to clean up any data it may be hanging on to that allows it to perform future compensation.
Finally, the "BPEL Compensate" throws a BPEL exception to cause the BPEL process to compensate itself.
The final BPMN process that takes advantage of this story looks as follows:
Here we execute the BPEL_Compensate AIS if either an Ad Hoc request to cancel the process arrives or an unexpected exception is trapped.