Web Services and Flows (WSFL), Page 2
A flow model's data flow specifies how the output message of a given business task is used by one or more (subsequent) business tasks. Put the other way round, the data flow specifies how the input message of a given business task is created from the results of one or more (preceding) business tasks or the input message of the flow itself. In that the involved message types typically don't match, the mapping from an output message to a subsequent input can involve transformations such as the renaming of message parts.
In WSFL, a data link is a relationship between two activities, A1 andA2, that describes that A2 uses the result data of A1.Figure 18.3 shows the signatures of the first few activities involved in the example flow model. The dashed arrows represent data links.
The following lines specify that the field customerInfo from the data part of the Order message, which was the result of the ReceiveOrder activity, is mapped to the record part of the Customer message that is the input to the ChargeCreditCard activity:
<dataLink source="ReceiveOrder" target="ChargeCreditCard"> <map sourceMessage="tns:Order" targetMessage="tns:Customer" sourcePart="data" sourceField="customerInfo" targetPart="record"/> </dataLink>
Flow model: inputs, outputs, and data links.
As the example shows, WSFL allows the data flow to be specified independent from the control flow, as long as the execution order constraints still guarantee that a message is produced before it is used by another activity. Generally speaking, the data flow has to be parallel to the control flow.
It is possible that an activity receives data from multiple other activities (a data join). In this situation, WSFL allows for the detailed specification of the materialization of that activity's input message, using either an override technique such as "last writer wins," or a merge technique that can be specified via an XSL transformation with multiple inputs. This kind of elaborate container materialization is not needed for the current example, and so it is not detailed further here.
If you put the ingredients described in the previous sections together, you have already completed the specification of a simple flow model involving activities that are implemented by internal operations, like this:
<flowModel name="cellPhoneOrder"> ... <activity name="CheckCreditHistory"> <input name="CustomerData" message="tns:Customer"/> <output name="Result" message="tns:CreditWorthiness"/> <implement> <internal>...</internal> </implement> </activity> ... <controlLink source="ReceiveOrder" target="CheckCreditHistory" transitionCondition="customer/id=null" /> ... <dataLink source="ReceiveOrder" target="CheckCreditHistory"> <map sourceMessage="Order" targetMessage="Customer" sourcePart="data" sourceField="customerInfo" targetPart="record"/> </dataLink> ... </flowModel>
Flows as Compositions of Web Services
The previous sections introduced the basic building blocks of a flow, without focusing too much on the actual realizations of the flow's activities. Although those realizations could be anything from manual realizations by human beings to an assembler program, the goal of WSFL is obviously not so much the composition of flows that coordinate internal implementations, but rather the composition of flows that perform the coordination of Web services, where the Web services implement individual activities.
For that, WSFL first introduces the notion of a service provider as an abstraction for a business partner that offers one or more WSDL services that are used within the flow model. Second, a WSFL activity can then refer to a specific operation that a specific service provider provides, as an alternative to the internal implementation you already saw in the previous sections.
Service Providers and Service Provider Types
Service providers are abstractions for the concrete business partners with which a flow model interacts. Service providers are declared in a WSFL flow in the same way that variables are declared in a Java program. A type ("service provider type") is assigned to each service provider. The type is essentially nothing but a predefined list of WSDL portTypes, and it gives a formal representation of the service or services that each service provider must offer to participate in the flow. The actual binding between a service provider variable of a given type and a concrete business partner is a separate step, which is described by the locator element.
The distinction between a service provider and a service is an important one: Flow models specify the usage of a service instance of a given type, rather than the service itself. Several flows can use a single Web service simultaneously, whereas a single flow model can use more than one provider of a given service type. (Whether or not the service type is supported or bound to the same service is in principle irrelevant; see the section Locators, however). Coming back to the example, Figure 18.4 shows an updated version of the flow model, where three steps have been outsourced to business partners.
Flow model using Web services.
WSFL requires that the business partners with which the flow model interoperates are declared as service providers (of the appropriate type). In the example, there are two, which are made available at the flow model level as follows:
<flowModel name="cellPhoneOrder"> <serviceProvider name="Partner1" type="CreditServicesProvider"/> <serviceProvider name="Partner2" type="LogisticsProvider"/> ... </flowModel>
This simply declares two global variables at the flow level to be service providers of the specified service provider type. A service provider type in WSFL describes the external interface a business partner makes available, which can consist of multiple port types and multiple operations.
The specification of service provider types is also part of the WSFL definitions, in an element preceding the flow model.
In the example, the following lines indicate that the CreditServicesProvider offers two operations from two port types (and a similar definition for the LogisticsProvider, which is not shown here):
<serviceProviderType name="CreditServicesProvider" <portType name="creditHistoryHandler"> <operation name="check"/> </portType> <portType name="creditCardHandler"> <operation name="charge"/> </portType> </serviceProviderType>
The declaration of the service providers with which a flow interacts is separated from binding those service providers to actual business partners that offer the required services (according to the associated service provider type). Although it is possible and often desirable to always use the same business partner as a certain service provider, sometimes more dynamic binding mechanisms are needed. A foremost example is UDDI lookup: Service providers of a given type are looked up in a UDDI directory according to some criteria, then the most suitable service among the retrieved set (according to some quality of service criterion) is selected and bound.
In WSFL, the locator element covers the entire range of possible bindings, locating the actual business partner that acts as a specific service providereither statically or dynamically.
The example has so far declared two global variables at the flow level that represent business partners with which the flow is interacting, and has defined the required interface the partners have to provide, described by their service provider type. It has not yet specified the concrete partners, that is, how these variables are bound. A WSFL locator element specified this as part of the service provider declaration.
The simplest kind of locator in WSFL is a static locator, which directly refers to a WSDL service that provides the required operations. Observe that the service is then identified by its namespace-qualified name, as defined in the corresponding WSDL file. It appears in the example as follows:
<flowModel name="cellPhoneOrder"> <serviceProvider name="Partner1" type="CreditServicesProvider"> <locator type="static" service="abc:qualityCreditServices"/> </serviceProvider> ... </flowModel>
A second possibility is a dynamic locator that uses UDDI (see Chapter 9) to dynamically find a suitable service provider of the required type:
<flowModel name="cellPhoneOrder"> ... <serviceProvider name="Partner2" type="LogisticsProvider"> <locator type="uddi" bindTime="firstHit" selectionPolicy="user-defined" invoke="leastcost.wsdl"> <uddi-api:find_service businessKey="uuid_key" generic="1.0" xmlns:uddi-api="urn:uddi-org:api"> ... </uddi-api:find_service> </locator> </serviceProvider> ... </flowModel>
In this example, the flow engine uses UDDI to locate Partner2, the logistics provider, when an operation this partner provides is needed for the first time (firstHit). The flow engine executes the specified UDDI query, which returns a list of possible providers, which the flow engine then filters using a user-defined routine to return the cheapest provider. This locator type provides for many more options not detailed here.
There are other locator types. Internal activity implementations (as described in the Flow Modeling Concepts section) are actually represented as operations a service provider implements with a locator type of local (The earlier discussion omitted that detail.) Finally, with a locator of type mobility it is possible to use a data field from a message to locate a service provider.
A more thorough description of locators and their options is in section 4.4.3 of Web Services Flow Language (WSFL) (see the References section).
Outsourcing Activity Implementations: Export
After the service providers the flow model uses are declared, and given the definition of their associated service provider types, the implementation of an outsourced activity simply needs to reference an operation a service provider offers, as shown in the following example:
<activity name="CheckCreditHistory"> ... <performedBy serviceProvider="Partner1"/> <implement> <internal> <target portType="creditHistoryHandler" operation="check"/> </internal> </implement> </activity>
Thus, the Check operation that is part of partner 1's CreditHistoryOperations port type implements the flow model's CheckCreditHistory operation. This is well defined, because partner 1 has been declared to be of type CreditServicesProvider, and thus is guaranteed to provide that operation.
The model WSFL uses for outsourcing an implementation is in fact more complicated than presented here. The concept, however, is essentially the one that is presented here. It would not make sense in this short overview to go over the details of WSFL activity implementations. See Section 4.6 in the Web Services Flow Language (WSFL) (see the References section).
Exposing Flows as Web Services
Having built a flow model implementing the cell phone ordering process, the next step is to make it available so others can use it. To do this, the flow model itself is defined as a service provider implementing a particular service provider type.
You can denote the flow's individual activities that implement this service's operations by "exporting" them, that is, by making them available for direct interactions with service clients. Still left open is how a flow's concrete instance actually comes to life and vanishes again after it is completedthis is addressed by the flow model's life cycle operations.
After you have these ingredients together, it is possible to use WSDL services and other WSFL flows to recursively compose flows.
Flow Model as Service Provider
Figure 18.5 highlights the interface to which the flow model's client connects. The flow's interface contains four operations, one inbound and three outbound, depicted as arrows that are graphically connected to the activities they implement via dashed lines. Initially, the client using that interface sends a request for a new cell phone, upon which he receives either a rejection or a bill, which eventually is followed by a delivery note (and the physical delivery of the phone, which is outside the scope of a software solution).
Externalizing a flow as a Web service.
For this, you can define a port type and service provider type as follows:
<portType name="cellPhoneOrderHandler"> <operation name="acquireCellPhone"> <input name="theOrder" message="tns:Order"/> </operation> <operation name="reject"> <output name="theRejection" message="tns:RejectionNotice" /> </operation> ... </portType> <serviceProviderType name="cellPhoneOrderProvider"> <portType name="cellPhoneOrderHandler"/> </serviceProviderType>
Given these definitions, the flow model can be defined to be a service provider of that service provider type by the actual flow model declaration:
<flowModel name="cellPhoneOrder" serviceProviderType="cellPhoneOrderProvider"> ...