http://www.developer.com/

Back to article

Web Services and Flows (WSFL)


September 12, 2002


This is Chapter 18: Web Services and Flows (WSFL) from the book Java Web Services Unleashed (ISBN:0-672-32363-X) written by Robert Brunner, Frank Cohen, Francisco Curbera, Darren Govoni, Steve Haines, Matthias Kloppmann, Ben Marchal, Scott Morrison, Arthur Ryman, Joe Weber, and Mark Wutka, published by Sams Publishing.


Chapter 18: Web Services and Flows (WSFL)

Chapter 18: Web Services and Flows (WSFL)

By Francisco Curbera and Matthias Kloppmann

In This Chapter

  • Service Flow and Service Composition
  • Flow Modeling Concepts
  • Flows as Compositions of Web Services
  • Exposing Flows as Web Services
  • Public and Private Flows
  • Global Models
  • References

The overall aim of Web services is to provide a standards-based framework to enable application-to-application interaction. Simple interactions, in particular stateless ones, can be modeled as single operation invocations or message exchanges with a service; WSDL and SOAP provide convenient support for this type of basic interaction. Richer interactions typically involve multiple invocations flowing between two or more services in a peer-to-peer setting—that is, a scenario in which all participants potentially act as both clients and servers. This is the model of interaction prevalent even in simple business transactions, both in the business-to-consumer and (especially) in the business-to-business scenarios. Even a process as simple as ordering merchandise online involves at least three parties—a customer, an e-commerce retailer, and a shipper—as well as direct interactions between the three of them.

The full potential of the Web services framework will not be realized until complex interactions of this kind are properly supported. Although no single standard has yet emerged, Web services flow (or process) languages, such as the Web Services Flow Language (WSFL) and XLANG), provide the means to deal with them. This chapter reviews the basic concepts underlying these languages, drawing mainly from WSFL.

Service Flow and Service Composition

Complete representations of complex service interactions rely on two basic concepts: service flow and service composition. The service flow is a description of how the service operates. In business environments, the service flow is a representation of the business process that it implements. By revealing the internal operation of the service, the flow lets users and possible business partners know how the service should be used. In particular, the flow describes the order in which the operations the service provides should be used, and the logic the service follows to process requests. Following a long-standing tradition in the field of business process modeling, WSFL uses a flow model to represent service flows. The flow model itself is presented in the section Flow Modeling Concepts.

A flow's individual steps can be realized through a multitude of possible implementations, from manual realizations performed by people to automatic implementations performed by software. The usage of Web services as particular realizations of the individual steps of a flow is described in the section Flows as Compositions of Web Services.

Flows themselves are of course services, too, though more complex ones. It must therefore be possible to make them available as Web services. The section Exposing Flows as Web Services; shows how this can be done.

Flows can provide different levels of description of the business process followed by a Web service. The complete description allows a flow language interpreter (a flow engine) to actually implement all the service functionality with no other input than the service flow specification itself. Typically, this level of description is not published, because it may reveal details of the hosting enterprise's operation or its trade secrets. The complete flow is in this case referred to as the private flow of the service. A simplified flow is published instead, containing just the information partners need to interact with the service. This public flow differs from the private one only in the level of detail provided, not in the underlying representation model. The section Public and Private Flows; deals with public flows.

Service composition is the second fundamental concept that is required to represent complex service interactions. Composition refers to the act of putting together two or more existing services to provide new functionality not present in the original ones, either in the form of a new service or in the form of a distributed service interaction. A flow typically accesses other Web services in the course of its operation, thus becoming a composition of services itself: It defines a usage pattern for existing services and optionally offers the composed functionality as a new service. A second type of composition occurs when multiple services interact following a certain interaction pattern to achieve some business goal. The nature of this composition is intrinsically distributed: Unlike the flow-based composition, these compositions are not orchestrated from a single point of control or flow engine. Service composition in WSFL is described in some detail in Flows as Compositions of Web Services; and Global Models.

The rest of this chapter develops the themes outlined here in some detail, using the flow depicted in Figure 18.1 to introduce the basic concepts of service process and service composition. You will notice a significant difference between this and other chapters in the book: There is no Java code provided here. The reason, obviously, is that there is no support available yet for any of the proposed Web services flow languages. The goal of this chapter is thus limited to introducing the fundamental concepts of service flows and compositions.

Figure 18.1
Cell phone ordering service sample flow.

Flow Modeling Concepts

In WSFL, flow models are used for the specification of complex interactions of services. A flow model describes a usage pattern of a collection of available services, so that the composition of those services provides the functionality needed to achieve a certain business goal—that is, the composition describes a business process. The flow model specifies precisely how those services (steps in the flow) are combined, specifying in which order they have to be performed (including the possibility of concurrent execution), the conditional logic deciding whether an individual step or a group of steps have to be performed at all or should be looped, and the passing of data between the involved steps.

Figure 18.1 shows an example of a flow model describing a simplified ordering process for a cell phone that continues and evolves throughout this chapter. It consists of a set of business tasks that are executed in a certain order, although some tasks may be skipped. The example flow starts with the receipt of an order for a new cell phone. If the requestor is not known as a customer, the credit history is checked first, and then a customer account is created. Neither of these tasks need to be done for an existing customer. Depending on retrieved knowledge about the requestor, the order might be rejected. Otherwise, the order is processed. The credit card is charged, a bill is sent, a new phone number is assigned, the phone is sent, and so is a note informing of its delivery.

Data produced by a certain task in the flow may be used by a subsequent task; for example, the customer account data is used to send the bill.

From the example, you can already see that the key ingredients for the description of a flow model are the individual business tasks that have to be executed, the specification of the control flow describing the order of their execution and the conditional logic, and the specification of the associated data flow describing the passing of data between them. In WSFL, those three concepts are described by activities, control links, and data links.

Activities

An activity is a single step in a flow. It represents a business task that potentially has to be performed as part of the business process the flow model describes. Whether it is actually performed during the execution of a specific flow depends on the conditional logic of the control flow into which it is embedded.

WSFL distinguishes between an activity and its implementation. The implementation describes an actual operation that is invoked when the activity is reached during execution of the flow. The activity, on the other hand, describes how this operation is embedded into the flow. An operation in this context can be anything needed to realize the particular business task. The most obvious realization is the invocation of a piece of code. Another very common realization in existing workflow products is the involvement of human beings performing a task manually.

In the example, the CheckCreditHistory activity is described by the following WSFL fragment:

<activity name="CheckCreditHistory">
 <input name="CustomerData" message="tns:Customer"/>
 <output name="Result" message="tns:CreditWorthiness"/>
 <implement>
  <internal>
   <!-- Implementation is provided by check method of
      an EJB -- outside WSFL scope -->
   <ns1:ejbMethod xmlns:ns1="..."
           ejbNameJndiName="/finance/creditHistory"
           operation="check" />
  </internal>
 </implement>
 <!-- Other properties describing embedding into
    (control and data) flow -->
</activity>

The fragment specifies that the CheckCreditHistory task expects a message of type Customer and produces a message of type CreditWorthiness. Both messages are WSDL messages as described Chapter 11.


Note

The tns (this name space) prefix is needed because messages are actually XML-qualified names that are qualified by associated name spaces.


For the example, we assume that the activity is implemented by a certain EJB's check method. Note that the specification of the actual implementation is from a different name space, because WSFL addresses this as an extensibility element outside the WSFL scope.

Additional properties of the activity relate to its embedding into the control and data flow, which is covered in the following section.

Control Flow

The control flow of a flow model specifies the execution order of the individual business tasks to be performed, and the conditional logic specifying whether they should be performed at all, or possibly looped. The need for executing two business tasks in a certain order follows from logical dependencies between them; if no such dependency exists, they can be performed concurrently, thus speeding up the execution of the flow.

In WSFL, a control link is a relationship between two activities, A1 and A2,that prescribes an execution order: A1 has to be completed before A2 can be started. In WSFL, the set of all activities and the set of all control links together describe a directed, acyclic graph.

Figure 18.2 has more control flow detail for the first part of the example flow model. Here, the control link between the ReceiveOrder activity and CheckCreditHistory activity indicates that the latter cannot be started until the former has completed. Whether it is actually started depends on the control link's optional transition condition attribute, which is evaluated at the flow's run-time. Depending on that evaluation, control is either passed along the control link, or the control link marks the start of a dead path, which is eliminated from the flow during its run-time.

WSFL doesn't distinguish between alternate branches where one is taken depending on a certain condition (switch) and parallel branches that are all taken concurrently (fork). In the WSFL model, multiple control links originating from the same activity always denote a fork, possibly followed by a dead-path elimination of some of the parallel branches.

Figure 18.2
Flow model: control links, transition conditions, and join conditions.

In the example, the following lines specify that this path is to be taken only if the activity ReceiveOrder returned no customer ID, that is, when nothing is known about the customer:

<controlLink source="ReceiveOrder" target="CheckCreditHistory"
 transitionCondition="customer/id=null" />

The two control links leading to the ChargeCreditCard activity specify a control join, stating that this activity can be started only after both the ReceiveOrder and CreateCustomerAccount activities are complete. Completion is achieved either by successful execution or by dead path elimination. When an activity is the target of more than one control link, a WSFL join element associated with the activity describes how the activity is dealt with.

In the example, the following lines state that the ChargeCreditCard activity is executed only after all its incoming control links have been evaluated, synchronizing the parallel paths (deferred evaluation of the join element, the only option currently offered by WSFL), and only if at least one of those control links evaluated to true:

<activity name="ChargeCreditCard">
 <input name="CreditCardData" message="tns:CreditCard"/>
 <output name="Result" message="tns:CreditCardChargeRecord"/>
 <implement>...</implement>
 <join condition="link1 OR link2" when="deferred" />
</activity>
<controlLink name="link1"
 source="ReceiveOrder" target="ChargeCreditCard"
 transitionCondition="customer/id != null &amp;&amp;
            customer/credit=ok " />
<controlLink name="link2"
 source="CreateCustomerAccount" target="ChargeCreditCard" />

Data Flow

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>

Figure 18.3
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.

Flow

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.

Figure 18.4
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>

Locators

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 provider—either 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.


Note

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.


Note

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 completed—this 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).

Figure 18.5
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">
 ...

Exported Activities

You have previously seen (in the section Outsourcing Activity Implementations: Export) how you can outsource an activity's implementation to an external service provider by using the internal element to specify an activity's implementation. The use of the internal element is necessary when the connection to the external provider is kept private to the service, in the sense that it is not carried through a public WSDL interface; that is, it is not mediated by an operation in the service provider type that the flow declares.

Alternatively, an activity's implementation can be provided by exporting it. Exporting an activity makes it visible to the flow's clients in the form of an operation on the flow's service interface. In this case, an export element replaces the internal element used before, and a nested target element identifies the operation in the flow's own interface that is mapped to this activity.

Detailing the Reject activity to make use of export produces the following WSFL fragment:

<activity name="Reject">
 <input name="orderData" message="tns:Order"/>
 <implement>
  <export>
   <target portType="cellPhoneOrderHandler" operation="reject"/>
   ...
  </export>
 </implement>
 ...
</activity>

When an activity's implementation is exported, the flow engine executes the activity by either receiving an invocation from a client (if the operation to which the activity is exported is one-way or request-response—that is, an inbound operation), or by invoking an operation on a partner (when the operation mapped to the activity is an outbound operation—that is, notification or solicit-response). For example, the reject operation in the preceding example is a notification operation on the phone ordering service interface, but corresponds to the invocation of a one-way operation in the customer interface (which is to say that the customer must be able to receive the rejection, and implies a peer-to-peer interaction model, see Global Models). Because of the uniform treatment that WSDL gives to inbound and outbound operations, WSFL deals with both cases in the same way.


Note

In WSFL, a plug link can be provided inside the export element to indicate the operation in the target provider that is actually being invoked. You do not need to be concerned with this level of detail at this point. Plug links are introduced in the section Plug Links; additional details can be found in sections 4.5 and 4.6 of the WSFL specification (see the References section).


Note that in the example the message types of the activity and the exported operation don't match. In this case, an additional map element is required to perform the message transformation. The full specification of the export element from the preceding example would then be as follows:

  <export>
   <target portType="cellPhoneOrderHandler" operation="reject"/>
   <map sourceMessage="tns:Order" targetMessage="tns:RejectionNotice"
      sourcePart="data" sourceField="customerInfo"
      targetPart="customerData"/>
  </export>

Life Cycle Operations, Flow Input, and Output

Many instances of a given flow model can execute at the same time on the associated run-time infrastructure. In WSFL, a new instance of a flow is created with either the call or spawn operation.

Call is defined as a WSDL request-response operation where the input message is the input of the flow, and the output message is the result from the flow. Spawn is defined as a WSDL one-way operation where the input message is the input of the flow. Both operations can be exported (that is, exposed to clients) with a different name and signature.

Thus, the more precise definition of the sample flow model doesn't represent the AcquireCellPhone operation as the flow's first activity, but as an exported spawn operation, creating the flow instance and passing input data. It also introduces a node representing said flow input data (a flow source), replacing the previously present ReceiveOrder activity:

<flowModel name="cellPhoneOrder">
      serviceProviderType="cellPhoneOrderProvider">
 <flowSource name="ReceiveOrder">
  <output name="orderData" message="tns:Order"/>
 </flowSource>
 <export lifecycleAction="spawn">
  <target portType="cellPhoneOrderHandler" operation="acquireCellPhone"/>
 </export>
 <activity name="CheckCreditHistory">
  ...
 </activity>
 ...
 <controlLink source="ReceiveOrder" target="CheckCreditHistory"
        transitionCondition="customer/id=null" />
 ...

Additional life cycle operations are available:

  • A flow can be suspended through the use of the suspend operation. When suspended, the flow's execution is discontinued, but the flow still exists in its current state.

  • A suspended flow can be resumed through the use of the resume operation. Execution of the flow continues from the state where it was suspended.

  • The current state of a running flow can be queried through the use of the inquire operation. This enables a business partner to find out how far a given business process's execution (seen via its public flow interface, as described in the Public and Private Flows section) has already progressed.

  • A running flow can be terminated. This aborts the flow's execution at its current state.

All the life cycle operations are offered as WSDL operations taking a flow instance ID as a parameter. The operations can be exported via an export element, as in the example in the Exported Activities section.

Recursive Composition

You have seen that a flow utilizes operations provided by several other services as the implementation of its activities. Another way to put this is to say that a flow defines a composition of services by specifying a certain usage pattern of its service providers' functionality. That is, the flow combines the operations made available by its providers to achieve a given compositional goal. You have also seen that a flow model itself can implement a certain service provider type—that is, it can become a service itself, offering a set of WSDL interfaces to possible clients. In particular, the flow could become part of yet another service composition itself. The result is a mechanism by which services can be recursively composed following a flow composition model.

In general, this form of composition assumes a peer-to-peer interaction model between services, in which the flow can invoke and be invoked by other services. However, the compositional model provided by flows is a centralized model, in which the composition is fully orchestrated from a single control point: the executing flow engine. Fully distributed compositions of services are introduced in the section Plug Links.

A special case of flow composition is based on hierarchical interactions between services, as opposed to the more flexible peer-to-peer model. In this case, an entire flow model can provide the implementation of a single activity of another flow—that is, it becomes a sub-flow of the invoking flow. You can achieve this kind of composition by using the flow model's Call operation to implement the other flow's activity. Input data from the activity is then passed to the flowSource of the sub-flow, and data from the sub-flow's flowSink is passed back to become the output of the activity.

Public and Private Flows

The introduction to this chapter mentioned the important fact that flow languages are used both to provide users of the service with a description of its behavior, and to actually implement the service. When used to describe service behavior, the information provided is strictly limited to what partners need to know to successfully interact with the service; implementations, on the other hand, must contain all the details that would enable a compatible interpreter to execute the service on behalf of requesters.

This section briefly reviews these two requirements and shows how a service's public and private behavior are related in a typical case.

Defining Service Behavior

The behavioral description of a service is the first and most important task of a flow language in the Web services space. It is intended for the service customer and provides the information that enables the customer to effectively use the service and understand how its requests will be processed. In particular, this includes:

  • The correct order in which the operations of the service need to be invoked.

  • The alternative paths that the execution of the service may follow based on the received information.

  • The set of steps that represent the possible states in the execution of the service, which the requester could possibly need to query in the course of a long-running interaction (as when using a lifecycle inquire operation; see the section Life Cycle Operations, Flow Input, and Output).

  • The data flow between steps, as needed to support the flow of control.

All this information can be easily encoded through the use of the flow model described in previous sections. A service description based on a flow model, on the other hand, does not imply anything about the actual implementation of the service. Implementation independence is a foremost concern in designing the Web services framework. Many services are likely to be implemented using technologies that don't rely on flow models, such as traditional object oriented languages. Regardless of the implementation technology, these services require a standards-based description of their behavior to facilitate their use and integration with other services.

Implementing a Service as a Flow: Private Versus Public Flows

On the other hand, the language necessary to provide a behavioral description is fundamentally enough to describe the full execution of that behavior on a compatible interpreter such as a traditional workflow engine. You just need to make sure that the language allows the specification of additional implementation details, such as what program or service to invoke at each activity in the flow and a set of endpoint and quality-of-service properties (such as security, transactionality, timing, and so on.) You have already seen that the WSFL model enables you to do this within the same language that you use for public flows.

There are two advantages to having a single language for both purposes: First, a common language enables developers to easily transform existing business processes (which are commonly encoded as flows) into actual Web services; second, a flow language capable of encoding actual implementations defines a platform-independent, standard, portable execution language for Web services. This implementation language relies on Web service standards (basically, WSDL and related specifications) to provide implementation details, and can be executed on any vendor's standardized flow engine.

A flow that provides the service implementation is usually not suitable as a public description of service behavior; on one hand, it may reveal information private to the service provider or even trade secrets, whereas on the other hand, the actual implementation flow is usually too complex and cluttered with details that have no relevance to customers. To highlight this difference, it's common to refer to the actual implementation flow as the private flow of the service, and to its simplified public description as the public flow.

Defining a Public Flow

The difference between a private flow (one with complete implementation information) and a simplified (or customer-facing) public flow is thus fundamentally one of authoring style. Consider now the cell phone ordering service that has served as an example.

The original process was depicted in Figure 18.5. A simplified flow is shown in Figure 18.6. Here, only the steps that are relevant to the interaction with the ordering customer are shown. Note, for instance, that the steps of checking credit history or creating a new account are not present in the simplified flow. The service user needs to know only that his request will be either rejected (resulting in a rejection message being sent back to him), or accepted (resulting in his credit card being charged and a bill sent). Likewise, if you proceed downstream through the flow, you will see that the activity AssignPhoneNumber is missing in the public flow, which is explained by the fact that this operation has internal relevance to the cell phone company but not to the customer.

Figure 18.6
Public flow.

The simplification of the flow is not limited to revealing fewer internal steps to the customer. First, observe the modification of the control flow, as the double control dependencies at SendRejection and ChargeCreditCard are removed. Note also that the relationship established with a shipper service in activity ShipPhone is not reflected in the flow of Figure 18.6, because this is a private detail that the service does not want to reveal to customers or competitors. In terms of the definition of the corresponding activities, you would have in this case an activity without an implementation block.

Drawing from this example, the typical relationship between the private and the public flow can be summarized as follows:

  • Public flows have only a subset of all the activities present in the private flow. The activities present in the public flow are those needed to support the proper flow of control and to provide users with information on the execution state.

  • Public flows have simpler flow of data and control, but provide full information about the sequencing of service operations.

  • The implementation of certain activities is not exposed in public flows.

  • A private flow and its corresponding public version both support the same customer-facing interfaces. From the customer perspective, both flows show the same service provider type.

Regardless of the differences between a service's private and public flows, both should match the observable behavior of the service: The same external interactions with the customer need to be present in both representations, and the sequencing and control dependencies between them must be equivalent, in the sense that the two descriptions should accept as valid the same sequences of message exchanged between a client and the service. Making sure that this type of equivalence holds can be hard to show in the case of complex flows. The important point to keep in mind, however, is that from a service user's perspective, both flows should behave in exactly the same way.

Global Models

Up until now you've been dealing with the problem of specifying the behavior of a single Web service, either in executable form (private flow) or as a public contract (public flow). In practice, every transaction involves at least two parties, each of which can be characterized in general as a Web service. Complex transactions can typically involve three and more participants directly interacting with each other. Using the flow model described in the previous sections, you can represent the behavior of each one of the parties involved in a transaction. This, however, is not enough to fully specify how the interaction is carried out. What is still missing is a specification of the way in which all these parties need to interact to carry out a certain transaction. Global models are used in WSFL to specify the form of multiparty interactions.

To begin, consider the simplest case: an interaction between two services. A new service must be added to the example, representing an automated cell phone requester service—or customer—of the ordering service. The customer service and its interactions with the cell phone order services are shown in Figure 18.7.

Figure 18.7
Global model involving two parties.

Observe that the customer is modeled as a service itself, with a WSDL interface and a flow representing its behavior, in just the same way as the phone ordering service. In non-trivial interactions both the provider and the requester of a service need to send and receive messages at different points in their interaction; that is, both effectively behave as clients and servers simultaneously. The Web services interaction paradigm is thus naturally a peer-to-peer interaction model.

In WSDL terms, the customer interface includes one notification operation (sendOrder) and three in-only operations (getRejection, getInvoice, and getDelivery). The customer's public flow specifies the steps that need to follow the sending of the order before the customer's ordering process can be considered terminated: receiving the bill and receiving a note informing of the phone delivery. The customer can also receive a rejection message informing it that the request was not accepted.

Plug Links

In addition to the public flows of two services, Figure 18.7 depicts the interactions between the two in the form of connections between the two services. WSFL refers to these connections as plug links. Plug links are directional connections that represent the invocation of an operation of the target service by the source. WSFL models invocations as an ordered pair consisting of an outbound operation at the source (that is, a WSDL notification or solicit-response operation) followed by an inbound operation (WSDL one-way or request-response) at the target.

It is important to note here that WSFL makes the assumption that outbound operations in a WSDL interface represent a service's ability to invoke the corresponding inbound operation—that is, one whose signature is obtained by exchanging the input and output elements in the operation definition. Thus, WSFL interprets outbound operations by as proxies of the corresponding inbound operation, and a plug link is basically a symbolic representation of connection that exists between the proxy and the operation that it actually invokes on a given service.

The following is an example of a plug link as specified in WSFL syntax:

<plugLink>
  <source serviceProvider="customer" portType="customerPortType" 
      operation="sendOrder"/>
  <target serviceProvider="cellPhoneOrderService" portType="orderPortType" 
      operation="receiveOrder"/>
</plugLink>

In this example, the assumption is that sendOrder and receiveOrder have dual but matching signatures, as in the sample portTypes below:

<portType name="customerPortType">
  <operation name="sendOrder">
   <output message="tns:phoneOrder"/>
  </operation>
  ...
</portType>
<portType name="orderPortType">
  <operation name="receiveOrder">
   <input message="tns:phoneOrder"/>
  </operation>
  ...
</portType>

Provision must be made, however, for the case in which the types of the messages sent and received by the source and the target do not match, because in practice the connected services may have not been developed from a common design. WSFL allows for simple adaptation of the messages exchanged by means of a mapping mechanism similar to the one used with data links (see the section Data Flow). Thus, if the message that sendOrder sends has a different type from the message that receiveOrder accepts, a map specification can be included in the plug link to provide for the necessary data mapping:

<plugLink>
  <source serviceProvider="customer" portType="customerPortType" 
      operation="sendOrder"/>
  <target serviceProvider="cellPhoneOrderService" portType="orderPortType" 
      operation="receiveOrder"/>
  <map sourceMessage="sendOrderOutput" sourcePart="personalInfo"
    targetMessage="receiveOrderInput" targetPart="customerData"/>
</plugLink>

Global Models in WSFL

To describe a multiparty transaction, WSFL uses a new construct: the global model. A global model identifies the set of service instances that participate in the transaction (these are the service providers you saw in the section Flows as Compositions of Web Services) and uses plug links to define the interactions between them.

The customer-to-phone order service transaction has a very simple global model with two providers and four plug links:

<globalModel name="phoneOrder">
  <serviceProvider name="customer" 
          serviceProviderType="abc:customerType"/>
  <serviceProvider name="cellPhoneOrderService" 
          serviceProviderType="cde:phoneOrderType"/>
  <plugLink>
   <source serviceProvider="customer" portType="abc:customerPortType" 
       operation="sendOrder"/>
   <target serviceProvider="cellPhoneOrderService" 
       portType="cde:orderPortType" operation="receiveOrder"/>
  </plugLink>
  <plugLink>
   <source serviceProvider="cellPhoneOrderService" 
       portType="cde:orderPortType" operation="rejectOrder"/>
   <target serviceProvider="customer" portType="abc:customerPortType" 
       operation="getRejection"/>
   <map ... />
  </plugLink>
  <!-- Additional plug links here -->
  ...
</globalModel>

Service providers (or service instances) identify a particular usage of a certain service, as opposed to the service itself. Service instances are typed according to a service type (a named set of WSDL interfaces, see Flows as Compositions of Web Services), and they are assigned a unique name within the global model. Plug links simply identify the source and target providers by their names, and the operations within those providers that are involved in the interaction.

Clearly, global models need not be limited to two-party interactions. Figure 18.8 shows a modification of the two-party phone order global model in which the order service has outsourced all the shipping functions to a third shipping service. The interaction between the customer and the phone ordering service is now limited to the initial ordering and billing. Both the phone ordering service and the customer have direct interactions with the shipping service: The phone ordering service transmits the phone shipment request to the shipper and lets it deal with all the shipping-related functions; the customer receives the delivery information directly from the shipper.

Figure 18.8
Global model involving three parties.

In the corresponding global model, there are three providers and three groups of plug links representing the interactions between them. You can see in the following example that the three service providers ("customer" on the left of the figure, "cellPhoneOrderService" in the middle, and "shipper" on the right) are declared at the top of the XML coding of the global model. In the rest of the global model, the customer to phone ordering service, phone ordering service to shipper, and shipper to customer interactions are defined in the form of sets of plug links connecting each pair of service providers. All possible pair-wise interactions between the providers are represented in the global model:

<globalModel name="phoneOrder">
  <serviceProvider name="customer" 
          serviceProviderType="abc:customerType"/>
  <serviceProvider name="cellPhoneOrderService" 
          serviceProviderType="cde:noShipperPhoneOrderType"/>  
  <serviceProvider name="shipper" 
          serviceProviderType="cde:shipperType"/>
  
  <!-- customer to phone order service links -->
  <plugLink>
   <source serviceProvider="customer" portType="abc:customerPortType" 
       operation="sendOrder"/>
   <target serviceProvider="cellPhoneOrderService" 
       portType="cde:orderPortType" operation="receiveOrder"/>
  </plugLink>
  ...
  <!-- phone order service to shipper link -->
  <plugLink>
   <source serviceProvider="cellPhoneOrderService" portType="cde:porderPortType" 
       operation="sendOrder"/>
   <target serviceProvider="shipper" 
       portType="fgh:shipperPortType" operation="receiveShippingOrder"/>
  </plugLink>
  
  <!-- shipper to customer link -->
  <plugLink>
   <source serviceProvider="shipper" portType="fgh:shipperPortType" 
       operation="deliveryNote"/>
   <target serviceProvider="customer" 
       portType="abc:customerPortType" operation="getDelivery"/>
  </plugLink>
  
</globalModel>

This example illustrates the distributed nature of the information that a global model is designed to capture. Note that in this case no single party has a complete view of the global interaction. The global transaction is a distributed composition in which two or more service providers are connected according to a certain interaction pattern to enable a level of functionality (a business goal) not provided by any service independently. Compare this form of composition with the type of compositions created when you use flows to define usage patterns of services, as described in Flows as Compositions of Web Services.

References

For more information on the topics discussed in this chapter, see these references:

Summary

This chapter reviewed the basic concepts of Web services flow languages, using WSFL as a model. Flow languages, and the fundamental notions of flows and compositions of Web services, are the basic pieces required to support complex, multiparty, and long- running service interactions, such as the ones involved in any realistic business-to-business transaction.

Authors of this Chapter

Francisco Curbera holds a Ph.D. in Computer Science from Columbia University, and is currently a Research Staff Member at IBM's T.J. Watson Research Center. He has worked for several years on the use of markup languages for application development and composition of software components, including the definition of the Bean Markup Language (BML), and the design of algorithms for managing XML documents. More recently, he has been involved in the definition and implementation of several Web services specifications. He is one of the authors of the Web Services Description Language (WSDL) and of the Web Services Flow Language (WSFL).

Matthias Kloppmann is a Senior Software Engineer with IBM Software Group's lab in Bvblingen, Germany. He holds an M.S. in Computer Science and Electrical Engineering from the University of Stuttgart. Matthias has many years of experience with building workflow systems, both in C++ and, more recently, in Java. He has participated in the creation of WSFL, the Web Services Flow Language, and the design of the XML and Web services extensions for MQSeries Workflow. Currently, Matthias is working as a workflow architect on WebSphere, IBM's J2EE application server.

Source of this material

This is Chapter 18: Web Services and Flows (WSFL) from the book Java Web Services Unleashed (ISBN:0-672-32363-X) written by Robert Brunner, Frank Cohen, Francisco Curbera, Darren Govoni, Steve Haines, Matthias Kloppmann, Ben Marchal, Scott Morrison, Arthur Ryman, Joe Weber, and Mark Wutka, published by Sams Publishing.

To access the full Table of Contents for the book

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date