by Lucas Jellema
Using events in Oracle SOA Suite 11g to have business processes impact each other in a meaningful way with maximum decoupling.
This article describes how events can be used in Oracle SOA Suite 11g to have business processes impact each other in a meaningful way with maximum decoupling. Specifically, this article describes a solution for fanning out Event Delivery Network (EDN) events to a more fine-grained level. This allows a single event to influence multiple running instances of a Business Process Execution Language (BPEL) process. The article uses the following Oracle SOA Suite 11g components:
Events are messages that are not targeted at a specific consumer. In a SOA environment where decoupling is one of our main objectives in order to reduce the dependencies between components and thereby enhance reusability and flexibility, events are a valuable way to share information in an extremely decoupled way.
The publisher of an event is the component that is aware of the business situation that is potentially interesting to other component. The component takes its responsibility and hands the event with the relevant details to the generic event handler infrastructure. The publisher is not aware of the subscribers to the event. It does not have to know what happens with the event and who will consume it.
Any component with an interest in specific business events can subscribe as a listener for these events with the event handler infrastructure. Whenever an event of a certain business event type is passed to the event handler, it will publish the event to all subscribed listeners. The consumers of the event do not need to know where the event originated and how it has been delivered to them.
The complete absence of a link between the event publishers and the event consumers is the main attraction of the usage of events and event drive architecture patterns. Collaboration without any dependencies is almost an architect's holy grail.
The Oracle SOA Suite 11g ships with an event handler infrastructure that is the intermediary for publishers of business events as well as the consumers of such events. This infrastructure is called the Event Delivery Network (EDN). Note: on a more technical level and with more development effort, JMS and AQ can also be used to work with events in SCA Composite applications.
One of the components that can subscribe with the EDN on specific events is BPEL. Mediator and BPMN are the other potential subscribers to EDN events. A BPEL process can receive EDN events in one of two ways:
Although the first option is useful, we will focus in this article on the second situation. When an event is consumed into a running instance, the event obviously has the capability of influencing that instance and the way it progresses. This pattern is used in situations where some business event may impact some and potentially many running business processes. Examples of such events could be fairly dramatic such as ban on trade with a certain country or company, , fire in a warehouse, the death of a client or the immediate withdrawal of a certain product or service. Less dramatic examples include a new client (in response to a marketing campaign0, start or end of a general discount period, staff member who called in sick or stock depletion of a certain product.
If a business condition is recognized as one corresponding to a predefined business event, the event is published. What should happen in response to the event, where and by which actors, is invisible and even irrelevant to the publisher of the event.
In this article we will consider the event Termination of Customer. This event signifies that the company should cease all dealings with a customer. Any sales cycles are to be aborted, no shipments may take place and any pending orders should be canceled. This influential event is published for example when a customer files for bankruptcy or is subject of certain federal investigations. As was stated before - the origin and cause of the event is not relevant to its consumers. They need to be fed the event with a simple payload: the identifier of the customer that is to be terminated.
One of these consumers is the BPEL process ProcessOrder. This process is started to handle the order from some customer, from the reception of the order to the shipment and the initiation of the subsequent invoice process. The next figure shows an outline of this process.
When a customer is terminated, all the running instances of the ProcessOrder process should be aborted. To this end, the scope DoAllTheWork in the BPEL process has an event handler (see Figure 4) that can consume a termination event and perform graceful abort of the process.
Events can be consumed in a running BPEL process instance based on correlation. The essence of correlation in BPEL is that every process instance gets assigned a unique key – the correlation identifier, derived from an incoming message or established inside the process - that is used later on to associate incoming messages or events to the instance. This incoming message or event needs to contain this unique keys in order to have successful correlation.
You may already spot the challenge we are facing in this article: there is one TerminateCustomer event that may have to impact many ProcessOrder BPEL instances. However, these instances can only correlate the incoming event based on their unique identifier. So any one event on EDN can be consumed by at most one instance of a BPEL process.
The ProcessOrder instances cannot be uniquely identified by the Customer Identifier, because there can be multiple orders being processed at the same time for the same customer. Instead, ProcessOrder instances are identified through their Order Identifier.
We need to fan out the event: we need to find a solution for how to convert the single TerminateCustomer event into AbortOrderForCustomer events for every order that is currently being processed for that terminated customer. The payload of the AbortOrderForCustomer event would contain the Order Identifier which can be used to correlate to exactly one instance of the ProcessOrder BPEL process.
What we need to achieve is clear: we need find out which finer grained details are associated with the business event and for each detail found, we need to publish an appropriate event. In this case, associated with the business object Customer are detail Order objects. For the TerminateCustomer event we need to find the running Orders for the customer and subsequently publish AbortOrderForCustomer Event for each Order. Publishing events is simple - Mediators can do that perfectly well in the Oracle SOA Suite.
The real question is how to find the running ProcessOrder instances. Here we will make use of the Oracle SOA Suite APIs that allow us to programmatically query instances. The API allows us to filter instances on the value of a Composite Sensor. If the Customer Identifier is exposed as Composite Sensor by the ProcessOrder composite, then the API allows us to retrieve only those instances that are associated with a specific customer identifier. And for each such instance we need its Order Identifier. A second Composite Sensor that contains the Order Identifier would be very helpful, because the API makes it easy to retrieve the value of a sensor for an instance.
With this in mind, a draft of a solution for this fan out challenge is created in Figure 6. It was first scribbled on a napkin during the Oracle SOA Suite Customer Advisory Board meeting during Oracle OpenWorld - clearly an inspiring setting. This draft contains the following steps:
Figure 7 illustrates one step in the progression from scribble to technical design, showing the components we need to implement in the SOA Composite application.
The remainder of this article demonstrates in detail the steps for implementing the SOA Composite application described above. It contains a BPEL process to execute the ProcessOrder business process. It also contains the Mediators and Spring Component to fan out the TerminateCustomer event to events for each order associated with the customer. It defines the EDN events. And finally it will show the application in action.
Of course the BPEL process discussed in this article is much simpler than a real production process would be. This does not however take away from the key elements and the event fan out mechanism.
Our work starts with the creation of a new SOA Composite application in JDeveloper 11g, equipped with the SOA Extension. This application is called FanoutEvent, as is the project that will contain the SOA Composite. All sources and artifacts described below are available from the sources that you can download for this article.
The ProcessOrder.wsdl file describes the Web Service that the BPEL process ProcessOrder will expose. The service has a portType ProcessOrder with a single asynchronous operation process. This operation takes an input message called ProcessOrderRequestMessage, with a single message part. This part is defined by the Order element in the ProcessOrder.xsd file.
The Order element is quite simple: a CustomerIdentifier and an OrderIdentifier are passed in, as well as the name of the required product, the number of items and the deliveryDetails.
The service is asynchronous and therefore defines the Callback PortType which also contains a single operation called processResponse with a simple single-part message, based on the ProcessOrderResponse element. By the way: for our discussion in this article, this response message is totally irrelevant.
The BPEL process component is added to the composite, based on the WSDL and XSD documents (Figure 10).
It contains a single scope called DoAllTheWork. In this scope, all the order processing could be implemented. For this article we do not need any such processing. All this scope contains is a Wait activity.
Earlier on, when we discussed the solution for the event level mismatch, two Composite Sensors were introduced. These sensors allow administrators to search for and filter on composite instances in the Oracle Enterprise Manager Fusion Middleware Control console. These also allow us to programmatically search for instances through the Java API.
In the Composite Editor using the sensor icon the Composite Sensor Editor is used to define the first Composite Sensor. It is called CustomerIdentifier and attached to the SCA Service exposed by the BPEL process. The value of this sensor is derived from the CustomerIdentifier element in the Order element in the request message. In other words: the value of this sensor is equal for an instance to the CustomerIdentifier for which the instance of ProcessOrder is created (Figure 11).
A second Composite Sensor is created to also expose the OrderIdentifier. We need to get hold of this value through the Java API in order to use it as payload in the AbortOrderForCustomer event that needs to be published (Figure 12).
The XML Schema Definition file events.xsd contains the type AbortOrderForCustomer Event which describes the payload for the EDN event AbortOrderForCustomer (Figure 13).
The AbortOrderForCustomerEvent contains children OrderIdentifier, CustomerIdentifier and motivation.
The AbortOrderForCustomer event is defined in the CustomerEvents.edl file, based on this AbortOrderForCustomerEvent definition. The next figure illustrates the definition of the event (Figure 14).
The situation at this point is as follows: a composite that exposes an asynchronous Web Service and two composite sensors. Additionally, the composite—or rather, the BPEL Component that it contains—is subscribed to the EDN event AbortOrderForCustomer.
In order to capture the event into a running instance of ProcessOrder, we need to set up a correlation for the consumption of the event. This means that we have to specify how the ProcessOrder instances are to be identified (through the identifier of the order) and when and how the unique key is assigned to an instance and when and how an incoming message or event is matched to this unique key.
First we need the correlation set OrderIdentifierCorrelationSet, based on the property called OrderIdentifier.
This means defining a unique key that is based on a single value.
The next step is the definition of the property aliases – the mapping between incoming messages or events and the property in the correlation set. Figure 17 shows how the property OrderIdentifier is mapped to the OrderIdentifier child element in the Order element in the incoming ProcessOrderRequestMessage. The property is also mapped to the OrderIdentifier element in the payload of the AbortOrderForCustomerEvent. This tells the BPEL engine that both the ProcessOrderRequestMessage and the AbortOrderForCustomerEvent contain the information required to uniquely identify the instance of the ProcessOrder with which they should be correlated.
One thing is still lacking from the BPEL process. We need to tell the BPEL engine when the unique key is set for an instance – and when it is used to feed an incoming event or message into an existing instance.
In this process, the correlation set is initiated when the ProcessOrderRequestMessage is received (and the instance first created). On the initial Receive activity, the correlation set OrderIdentifierCorrelationSet is indicated on the Correlations tab and the Initiate property is set to Yes.
The correlation set is used to feed the incoming AbortOrderForCustomer event into the existing instance of ProcessOrder. This happens in the onMessage event listener defined on the DoAllTheWork scope. The OnMessage activity should also have correlation configured, using the same OrderIdentifierCorrelationSet. This time Initiate is set to No because we do not want to assign the instance identifier. Rather, we want to use it to map the event to the running instance.
Figure 18 shows how correlation is configured for both the Receive and the OnMessage activities.
The TerminateCustomer event is defined in the CustomerEvents.edl file. This event needs to be intercepted by a Fan-out Mediator. This Mediator will subscribe to the TerminateCustomer event with the Event Delivery Network. When the event arrives, the Mediator is activated and in turn it will invoke a Spring Component.
The Spring Component uses the customer identifier from the payload of the TerminateCustomer event to find (through the SOA Suite Java API) all running ProcessOrder instances that expose a composite sensor CustomerIdentifier with the correct value. The Spring Component retrieves the value of the OrderIdentifier Composite Sensor for each of these instances and calls out for each instance to another Mediator to have the AbortOrderForCustomer event published to the EDN for that particular order identifier value.
The Events.xsd XML Schema Definition file contains the TerminateCustomer type that is used to define the payload of the TerminateCustomer event. This payload has to contain at least the customerIdentifier. The motivation child element is added for good measure.
The TerminateCustomer event is defined in the CustomerEvents.edl file. Its payload is based on the TerminateCustomer type in the XSD file. Figure 21 shows the edl file with the two business events recognized in this composite application.
The Mediator Component ConsumeTerminateCustomer is created based on the template Subscribe to Events. The event TerminateCustomer is selected from the CustomerEvents.edl event definition file as the event to which this this component subscribes.
The Mediator with its event subscription is added to the composite.
The next component that is added is the Mediator Component that publishes the event AbortOrderForCustomer. A simple WSDL document has been set up that defines the interface for this Mediator. It contains a single one-way operation called publishAbortOrderEvent that takes as its input an element based on the payload definition of the AbortOrderForCustomer event.
A routing rule is added to the Mediator, for publishing the AbortOrderForCustomer event. The transformation will do a one-to-one mapping from the request message's payload part to the event payload.
The Spring Component TerminateCustomerToAbortOrderEventTranslator is created in the composite.
The PublishAbortOrderEvent Mediator is wired to the Spring Component. This Mediator will provide the event publishing capability required by the Spring Component.
This creates an sca:reference in the Spring Component that can be injected later on into any bean created in the Spring bean definition file.
This reference is based on the PublishAbortOrderEventInterface Java Interface that is generated by JDeveloper for the WSDL that describes the Mediator's interface.
The CustomerToOrderEventProcessor Java Interface is created to describe the service provided by the Spring Component. This interface defines a method that can process a TerminateCustomer event and takes two string values as its input. The second method defined in the interface is a setter that is used to inject an implementation of the PublishAbortOrderEventInterface that was introduced in the previous paragraph. The Mediator PublishAbortOrderEvent, from which this Java Interface is derived, will provide this implementation through the sca:reference already created.
The sca:service provided by the Spring Component can now be defined in the Spring Bean definition file. The name it exposes is CustomerToOrderEventProcessor, and the service interface is specified by the Java Interface.
The WSDL based interface description of this sca:service—CustomerToOrderEventProcessor.wsdl—is generated by JDeveloper when the Spring Component's service is wired to a consumer, in this case the ConsumeTerminateCustomer Mediator, as shown in Figure 31.
The hull of the solution is created and all wires are in place. What is lacking is a Java Spring Bean that implements the Java Interface and does the real work promised by the sca:service of the Spring Component. This implementation is discussed next.
The Java Class CustomerToOrderEventProcessorImpl is an implementation of the CustomerToOrderEventProcessor interface. It implements both the processTerminateCustomerEvent method and the setPublishAbortOrderEventInterface method.
We can configure a Spring Bean based on this class as follows:
The bean is called CustomerToOrderEventProcessorBean. It provides the implementation for the sca:service; the link is established through the target attribute. The sca:reference (which is injected with the Mediator that publishes the AbortOrderForCustomer events) is set on the bean's publishAbortOrderEventInterface property.
The actual Class itself is fairly straightforward. It prepares an AbortOrderForCustomerEvent object—called "payload"—that will be passed to the Mediator in order to publish the event. The class retrieves a list of all orderIdentifiers from the ProcessOrder instances currently running for the customerIdentifier. It then iterates over these orderIdentifiers and invokes the Mediator for each of them.
The hardest work is done in the private method collectOrderIdentifiers. This methods connects to the Oracle SOA Suite Java API to query for all ProcessOrder instances with their CustomerIdentifier Composite Sensor set to the value in the customerIdentifier.
This API query uses a SensorFilter, into which the name of the composite sensor—CustomerIdentifier—and the value of that sensor are put. From each instance that is returned by this API, the value of OrderIdentifier sensor is retrieved in two steps. First, getSensorData() retrievs the collection of composite sensors for the instance. Second, a simple loop over this collection tries to find the entry for the OrderIdentifier sensor and reads its value when found. Each value thus determined is added to the collection of orderIdentifiers that this method returns.
The end result of everything described so far is shown in Figure 36. The normal business flow will be a call to the ProcessOrder_ep service that activates the ProcessOrder BPEL process. This instance is primed to consume the AbortOrderForCustomer event at any time during its lifetime. That event can be correlated into an instance based on the order identifier.
The exceptional flow starts with the Mediator that consumes the TerminateCustomer event. The Mediator retrieves the customer identifier from the payload of the event. It invokes the Spring Component TerminateCustomerToAbortOrderEventTranslator, passing in the customer identifier. This component uses the Oracle SOA Suite Java API to locate all composite instances with the customer identifier set in their composite sensors. The order identifier for all these instances is retrieved from the corresponding sensor and for each instance, the Mediator PublishAbortOrderEvent is invoked, passing in the order identifier. This Mediator publishes the AbortOrderForCustomer event.
This event is consumed by the ProcessOrder BPEL Process instance that correlates with the event based on the order identifier. The instance is then terminated.
Figure 36 shows the composite and visualizes the event transfer. Note, however, that there is no direct link between the Mediator publishing the event and the BPEL Process consuming the event: this interaction takes places via the Event Delivery Network that completely decouples publisher from consumer.
The SOA composite application is completely self contained. The application can be deployed to an Oracle SOA Suite runtime environment in the normal way.
You can open the JDeveloper application available in the resources for this article and deploy as indicated to your own Oracle SOA Suite environment of choice, as shown in the Figure 37.
When deployment is done, we start some instances of the ProcessOrder process. Select the FanoutEvent composite in the Oracle Enterprise Manager Fusion Middleware Control and press the Test button as is shown in Figure 38.
The Test Web Service page appears with a form that contains fields corresponding to the elements in the request message for the ProcessOrder_ep service. Only the customerIdentifier and the orderIdentifier are relevant to our purpose. Set them to ABC and 123A respectively, and press the button labeled Test Web Service to submit the request (Figure 39).
Start some more ProcessOrder instances for customer ABC, and also start some instances for customerIdentifier XYZ and for customerIdentifier PQR, according to the following list:
At this point, if we check in the Oracle Enterprise Manager Fusion Middleware Control, we see a list of instances. The composite sensors of these instances expose both the custom identifier and the order identifier (Figure 41).
Scenario: Customer XYZ is no longer a trustworthy business partner and all relations should be cut off immediately. The TerminateCustomer event should be published for this customer. As an indirect result of the publication of that event, we want all five ProcessOrder instances that are currently running for customer XYZ to be terminated.
EDN events can be published from the Enterprise Manager FMW Control - for test purposes. From the context menu on the soa-infra node, the option Business Events is selected.
When the Test button is pressed on the Business Events page, a popup window opens in which an event can be published. As shown in Figure 43, enter the XML Payload for the event in the text field and then click the Publish button.
The TerminateCustomer event is published on the Event Delivery Network, with the value XYZ for the customerIdentifier.
Before we look at the effects brought about by publishing this event, take a look at the following overview (Figure 44) of running instances filtered by the value XYZ for the CustomerIdentifier Composite Sensor, which gives us an idea of what should happen> The five listed instances should indicate that they have been terminated.
The EDN has a single subscriber for the TerminateCustomer event: the Mediator ConsumeTerminateCustomer in the FanoutEvent composite. This Mediator consumes the event for customer XYZ and should invoke the Spring Component TerminateCustomerToAbortOrderEventTransformer. This component should find all running instances of ProcessOrder for customer XYZ (we know from Figure 44 that there are five of them) and call the PublishAbortOrderEvent Mediator to publish the AbortOrderForCustomerEvent to the EDN for the specific order identifier.
Upon inspection of the message flow trace, it becomes clear that this is exactly what happened. Five calls took place to Mediator PublishAbortOrderEvent. This resulted in five AbortOrderForCustomer events for the five running orders. The message flow trace shows how one of these events caused a ProcessOrder instance to be terminated (Figure 45).
By drilling down into one of the terminated ProcessOrder instances and inspecting its BPEL Audit Trail, we can see a clear picture of what happened (Figure 46).
The AbortOrderForCustomer event for customer XYZ (the one that was terminated) and order 345X (the order that this BPEL instance was processing) have been consumed into this instance through correlation based on the orderIdentifier. The onMessage handler that captures this event caused the AbortThisOrder activity to be executed, abandoning the BPEL instance as intended.
All ProcessOrder instances for other customers are, of course, still running at this point. Only those dealing with orders for customer XYZ were terminated.
Through the use of business events, organizations can introduce a new level of decoupling. Any party—system, service, application, process—running into a situation that has been recognized as potentially interesting should tell the world about it by publishing an event to the generic event handler. Any party with an interest in one or more of these recognized business events can subscribe to the event handler to be notified when the events occur. Even though the consumer(s) and publisher of the event know nothing about each other, they still collaborate, after a fashion.
The Event Delivery Network in Oracle SOA Suite is one example of an event handler. Others are also available, or can be created with relatively simple means, including JMS and AQ.
When business events need the capability of impacting running processes—for example, BPM or BPEL—these events need to be correlated into the specific composite instance. However, when the business event is at a different level than the intended effect, such as the customer for whom all orders should be terminated, we face a challenge. Out of the box, correlation can take place into only one running process instance.
This article demonstrated how the event can be captured at the higher level and fanned out to the desired level of running instances. This is done using composite sensors, a Spring Component, the Oracle SOA Suite Java API to find the instances to correlate into and an second type of event tuned to the right level.
Lucas Jellema has been active in IT (and with Oracle) since 1994. An Oracle ACE Director specializing in Oracle Fusion Middleware, Lucas is a consultant, trainer, and instructor in diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, ADF, and Java. He is the author of the Oracle SOA Suite 11g Handbook, and a frequent presenter at JavaOne, Oracle Open World, ODTUG Kaleidoscope, Devoxx, OBUG and other conferences.