Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

WSFL: No Web service is an island

When Web services cooperate

Ajamu Wesley (awesley@us.ibm.com), Senior software architect, IBM Software Group
Ajamu Wesley is a Senior Architect within IBM's Emerging Internet Technology division. Ajamu develops technical strategy, and architecture while providing technical consulting services promoting the adoption of leading edge technologies. His current role is technical lead for Federated Identity. Ajamu has generated several external technical publications with his latest project being the authorship of "Programming WebServices", which is an instructive book for programmers focusing on WebServices and related technologies. He can be reached at awesley@us.ibm.com.

Summary:  This article is based upon a chapter from "Programming Web Services with Java" (Manning, 2002) that explains how you can use the flexible Web Services Flow Language (WSFL) to create new Web services by integrating other Web services. This is the second of a two-part series continues the example and shows how the different activities of each service can be linked together into a process flow. Used with permission of the publisher, Manning Publications, Co. Please see Resources for more book information.

Date:  01 Feb 2002
Level:  Introductory
Also available in:   Korean

Activity:  2464 views
Comments:  

[Editor's Note: This article is a programming example that illustrates the features of the Web Services Flow Language. It assumes that you already know the basic concepts behind workflow and WSFL. If you need a refresher, please see the Resources section for a selection of overview articles on WSFL.]

In Part 1, I outlined the various activity services that make up our portfolio management service between our fictional financial broker Strong.com, the New York Stock Exchange, and StockQuote.com's quoting services. I also introduced the flow model for our programming example. In this second part, I will explain what the complete picture of the process looks like including the flow and global models.

Control links and order of execution

When I last stopped in Part 1, I had shown defined the service provider type which is being specified in the flow model. Remember, the service provider type represents a set of port types which are implemented by service providers which implement our service provider type.

I have also identified the activities which are implemented by the flow, as well as the service providers which host those Web services which will ultimately implement the activities. The activities have been exported as WSDL operations, which must be implemented by the flow. So, I now have a Web service with three operations that are actually implemented by three separate Web services.

Now the flow model specifies the order of execution for the activities as well as the data exchanges between activities. The controlLink element represents an edge on the directed graph I presented in Part 1. The usage if controlLink is as shown below:

<controlLink source="retrieveStockQuote" target="creditCheck"/>

This controlLink indicates that the creditCheck activity is activated after the retrieveStockQuote activity completes successfully. Since there are no controlLink elements which specify the retrieveStockQuote activity as a target, this activity is considered a start activity (all start activities are scheduled for execution when the flow is instantiated).

Control links are fairly flexible. A fork operation indicates two parallel paths of execution. For example, let's say that after activity 'A' completes, I would like to perform activity 'R' simultaneously with activity 'W.' Let's assume that before I can perform activity 'K,' both activities 'R' and 'W' must complete. I could model this interaction with the following control links:


<controlLink source="A" target="R"/>
<controlLink source="A" target="W"/>
<controlLink source="R" target="K"/>
<controlLink source="W" target="K"/>


I define a fork after activity 'A' completes and a join operation before the 'K' activity is activated.

Control links may also specify transition conditions (Boolean expressions which are evaluated when an activity completes successfully). If the transition condition succeeds, the target activity is invoked. If the transition condition fails, the target activity is not invoked and parallel flows are evaluated to determine if the entire flow should be terminated.

The following controlLink indicates that after the creditCheck activity completes, the executeTrade activity should be invoked if the OutCheckCreditResponse messages 'response' part is true. The transitionCondition defines an XPath Boolean expression:


<controlLink source="creditCheck" target="executeTrade"
         transitionCondition="OutCheckCreditResponse/response"/>


Join activities that have multiple incoming control links may define a join condition that synchronizes the transition conditions. The join activity below indicates that the transition conditions for both activities 'R' and 'W' must evaluate to true before activity 'K' may be invoked:


<activity name="K">
    <joinCondition="R and W" when="deferred"/>
</activity>


The when attribute of the joinCondition element indicates when the Boolean expression is to be evaluated. The value of the when attribute is either deferred or immediate. Deferred evaluations wait until all transition conditions have been evaluated, while immediate evaluations process the transition conditions as they are evaluated. For example, if the 'R' activity terminated prior to the 'W' activity and the transition condition failed, then the join condition would wait until activity 'W' terminated and its transition condition was evaluated before evaluating to false.

Control links define the execution sequence for activities, but they do not provide instruction on how data is exchanged between the activities. Data links define message exchanges between activities. The decoupling of control and data links is useful because data is not necessarily transmitted when an activity yields execution to another activity.


Data exchange

The dataLink element defines a message exchange between a source activity and a target activity. The dataLink above indicates that a message was passed from the retrieveStockQuote activity to the creditCheck activity. While data links are decoupled from control links, a data link cannot be defined from a source activity to a target activity unless one or more control links exist from the source activity to the target.


<dataLink name="dataLink2" source="retrieveStockQuote" target="creditCheck">
       <map sourceMessage="OutRetrieveStockQuoteResponse"
          targetMessage="InCheckCreditRequest"
          sourcePart="meth1_outType" targetPart="stockPrice"/>
</dataLink>


The map element is used to map the output message from the source activity to the input message of the target.


<map sourceMessage="OutRetrieveStockQuoteResponse" 
	targetMessage="InCheckCreditRequest" sourcePart="meth1_outType" 
	targetPart="stockPrice"/>


The map element above indicates that the meth1_outType part of the OutRetrieveStockQuoteResponse message is assigned to the stockPrice part of the InCheckCreditRequest message.

OutRetrieveStockQuoteResponse is the output message generated by the retrieveStockQuote activity, while InCheckCreditRequest is the input message processed by the creditCheck activity.


FlowSource and FlowSink

So it is clear how messages are exchanged between activities. But where do the start activities receive data? For that matter, the InCheckCreditRequest message needs more information than the stock price: it also needs the client identifier so that I can access the client's account. I also need the number of shares the client wishes to purchase in order to calculate the transaction costs.

To better understand the overall process, I present a conceptual representation of the flow model in Figure 1.


Figure 1: The flow model for our example
Figure 1: The flow model for our example

The flow model defines a Web service which takes input and generates output -- so I need a means of accepting input and producing output. The flowSource and flowSink are special activities supported by WSFL specifically for this purpose. I assumed that when the flow is instantiated, an InPurchaseStockRequest message is provided by the flowSource activity. Additionally, an OutPurchaseStockResponse message is exchanged with the flowSink activity prior to the flow terminating:


<message name="InPurchaseStockRequest">
      <part name="stockSymbol" type="xsd:string"/>
      <part name="numOfShares" type="xsd:int"/>
      <part name="clientID" type="xsd:long"/>
</message>

<message name="OutPurchaseStockRequest">
    <part name="sucessfulTrade" type="xsd:boolean"/>
</message>


The dataLink0 data link indicates that a message is exchanged between the flowSource activity and the retrieveStockQuote activity.


<dataLink name="dataLink0" source="flowSource" target="retrieveStockQuote">
    <map sourceMessage="InPurchaseStockRequest" 
	targetMessage="InRetrieveStockQuoteRequest"
     sourcePart="stockSymbol" targetPart="meth1_inType1"/>
</dataLink>


The stockSymbol part of the InPurchaseStockRequest message is assigned to the meth1_inType1 part of the InRetrieveStockQuoteRequest message. The InPurchaseStockRequest message provides data input for the creditCheck activity via the flowSource activity as well. The clientID and the numOfShares message parts are mapped to the corresponding parts of the InCheckCreditRequest. Thus, once the flow is initialized the client identifier and the number of shares is inserted into a InCheckCreditRequest message. After the retrieveStockQuote activity completes, the stock price is known and added to the InVerfifyCreditRequest message.


<dataLink name="dataLink1" source="flowSource" target="creditCheck">
     <map sourceMessage="InPurchaseStockRequest" 
		targetMessage="InCheckCreditRequest" sourcePart="clientID" 
		targetPart="clientID"/>
     <map sourceMessage="InPurchaseStockRequest" 
		targetMessage="InCheckCreditRequest" sourcePart="numOfShares" 
		targetPart="quantity"/>
</dataLink>


The creditCheck activity generates an OutCheckCreditResponse message via the verifyCredit operation. The result message part is a Boolean value indicating whether the trade may be executed. The transition condition defined by the control link from the creditCheck activity to the executeTrade activity is evaluated.


<controlLink source="creditCheck" target="executeTrade"
      transitionCondition="OutCheckCreditResponse/response"/>


The executeTrade activity accepts an InBidRequest message as input. The stockSymbol and numOfShares parts of the InPurchaseStockRequest message populate the InBidRequest message.


<dataLink name="dataLink3" source="flowSource" target="executeTrade">
   <map sourceMessage="InPurchaseStockRequest" targetMessage="InBidRequest"
        sourcePart="stockSymbol" targetPart="symbol"/>
   <map sourceMessage="InPurchaseStockRequest" targetMessage="InBidRequest"
        sourcePart="numOfShares" targetPart="shareCount"/>
<dataLink>


The executeTrade activity generates an OutBidResponse message which indicates whether the trade was executed successfully.


<dataLink name="dataLink4" source="executeTrade" target="flowSink">
     <map sourceMessage="OutBidResponse" 
		targetMessage="OutPurchaseStockResponse" sourcePart="result" 
		targetPart="sucessfulTrade"/>
</dataLink>


The result message part of the OutBidResponse is passed to the flowSink activity as the output of the flow.


WSFL lifecycle operations

Our WSFL flow model defines a service provider type, or public interface for a Web service which is assembled from other Web services. Beyond the exported retrieveStockQuote, verifyCredit, and bid operations, the StrongPuchaseFlow service provider type supports lifecycle operations. All WSFL Web services must support the following lifecycle operations:

  • spawn
    Creates an instance of the flow model and returns an instance id.
  • call
    Creates an instance of the flow model and returns after the flow has completed. The call operation returns the result of the flow model instance.
  • suspend
    Suspends an instance of the flow model given an instance id.
  • resume
    Resumes a suspended flow model instance given an instance id.
  • enquire
    Queries the status of a flow model instance given an instance id. The result of the enquire operation is the status of the flow.
  • terminate
    Terminates a flow model instance given an instance id.

The WSFL global model

A WSFL global model binds Web service operations to operations defined by the aggregate service including exported and lifecycle operations. The global model for our example, shown in Listing 1, is conceptually represented in Figure 2.


Figure 2: The global model for our example
Figure 2: The global model for our example

Listing 1: The global model

<globalModel name="StrongStockPurchaseProcess" 
      serviceProviderType="StockPurchaseProcess">
    <serviceProvider name="NYSE_VirtualTradingFloor" 
	 type="VirtualTradingFloor"/>
    <serviceProvider name="StockQuoteRealTimeStockQuoteProvider" 
      type="RealTimeStockQuoteProvider"/>
    <serviceProvider name="StrongAccountManager" 
      type="AccountManager"/>
    <serviceProvider name="StrongPortfolioManager" 
      type="StockPurchaseFlow">
            <export>
               <source portType="StockPortfolioTrackerLifeCyclePT" 
				operation="spawn"/>
                  <target portType="StockPortfolioTrackerPT" 
				operation="purchaseStock"/>
            </export>
    </serviceProvider>

    <plugLink>
            <source serviceProvider="StrongPortfolioManager"
               portType="StockPortfolioTrackerPT" 
			operation="retrieveStockQuote"/>
            <target serviceProvider="StockQuoteRealTimeStockQuoteProvider" 
			portType="StockQuoteServiceImpl_Service" 
			operation="getStockPrice"/>
    </plugLink>

    <plugLink>
            <source serviceProvider="StrongPortfolioManager" 
			portType="StockPortfolioTrackerPT" operation="verifyCredit"/>
            <target serviceProvider="StrongAccountManager" 
			portType="AccountManagementPT" operation="checkCredit"/>
   </plugLink>

   <plugLink>
            <source serviceProvider="StrongPortfolioManager" 
			portType="StockPortfolioTrackerPT" operation="bid"/>
            <source serviceProvider="NYSE_VirtualTradingFloor" 
			portType="MarketExchangePT" operation="purchaseStockBlock"/>
   </plugLink>
</globalModel>

The global model is named StrongStockPurchaseProcess and defines a new service provider type (i.e. StockPurchaseProcess).


<globalModel name="StrongStockPurchaseProcess" 
    serviceProviderType="StockPurchaseProcess">
              ...
<globalModel>

The global model then declares the service providers which will be referenced within the document:

<serviceProvider name="NYSE_VirtualTradingFloor" 
	type="VirtualTradingFloor"/>
<serviceProvider name="StockQuoteRealTimeStockQuoteProvider" 
     type="RealTimeStockQuoteProvider"/>
<serviceProvider name="StrongAccountManager" type="AccountManager"/>
	

The NYSE_VirtualTradingFloor, StockQuoteRealTimeStockQuoteProvider and StrongAccountManager service providers are defined just as they were in the flow model. These service providers host the Web services which implement the underlying operations that I started with in the beginning of the chapter. The StrongPortfolioManager service provider is new and implements the StockPurchaseFlow which was defined by our flow model:

<serviceProvider name="StrongPortfolioManager" type="StockPurchaseFlow">
           <export>
              <source portType="StockPortfolioTrackerLifeCyclePT" operation="spawn"/>
              <target portType="StockPortfolioTrackerPT" operation="purchaseStock"/>
           </export>
</serviceProvider>



Notice that a locator is not defined for the StrongPortfolioManager service provider. Flow developers may define locators separately and implement the service provider type. The StrongPortfolioManager service provider indicates that the spawn operation is called implicitly when the purchaseStock operation is invoked. Thus by calling the purchaseStock operation, the flow model is instantiated.

The plugLink element binds an operation from a service provider's public interface to an operation implemented by a service provider:

<plugLink>
        <source serviceProvider="StrongPortfolioManager" 
   			portType="StockPortfolioTrackerPT" operation="retrieveStockQuote"/>
        <target serviceProvider="StockQuoteRealTimeStockQuoteProvider"
			portType="StockQuoteServiceImpl_Service" operation="getStockPrice"/>
</plugLink>


The plugLink indicates that the StrongPortfolioManager service provider's retrieveStockQuote operation is bound to the StockQuoteRealTimeStockQuoteProvider service provider's getStockPrice operation. This binds our flow model's public interface to the getStockPrice operation from our stock quote Web service.

<plugLink>
        <source serviceProvider="StrongPortfolioManager" 
   portType="StockPortfolioTrackerPT" operation="verifyCredit"/>
        <target serviceProvider="StrongAccountManager" 
   portType="AccountManagementPT" 
			operation="checkCredit"/>
</plugLink>



The verifyCredit operation from the StockPortfolioTrackerPT port type from the flow model is bound to the checkCredit operation of the Web service hosted by the StrongAccountManager service provider. Finally, the bid operation is bound to the purchaseStockBlock operation implemented by the service with the WSDL interface definition located at http://nyse.com/vtf.wsdl.

<plugLink>
           <source serviceProvider="StrongPortfolioManager" 
   portType="StockPortfolioTrackerPT" operation="bid"/>
           <source serviceProvider="NYSE_VirtualTradingFloor" 
   portType="MarketExchangePT" operation="purchaseStockBlock"/>
</plugLink>



Putting it all together

There is now enough information to finalize the workflow of our new Web service. You simply need to create a WSDL document that supports the relevant portTypes, operations and messages (see Listing 2).


Listing 2: Our finalized service in WSDL


          <message name="InBidRequest">
             <part name="symbol" type="xsd:string"/>
             <part name="shareCount" type="xsd:int"/>
          </message>

          <message name="OutBidResponse">
             <part name="sucessfulTrade" type="xsd:boolean"/>
          </message>

          <message name="InPurchaseStockRequest">
             <part name="clientID" type="xsd:long"/>
             <part name="numOfShares" type="xsd:int"/>
             <part name="stockSymbol" type="xsd:string"/>
          </message>

          <message name="OutPurchaseStockRequest">
             <partname="result" type="xsd:string"/>
          </message>

          <message name="InCheckCreditRequest">
             <part name="clientID" type="xsd:long"/>
             <part name="quantity" type="xsd:int"/>
             <part name="stockPrice" type="xsd:float"/>
          </message>

          <message name="OutCheckCreditResponse">
             <part name="response" type="xsd:boolean"/>
          </message>

          <message name="InRetrieveStockQuoteRequest">
             <part name="meth1_inType1" type="xsd:string"/>
          </message>

          <message name="OutRetrieveStockQuoteResponse">
             <part name="meth1_outType" type="xsd:float">
          </message>

          <portType name="StockPortfolioTrackerPT">
             <operation name="bid">
                     <input message="InBidRequest"/>
                     <output message="OutBidResponse"/>
             </operation>

             <operation name="verifyCredit">
                     <input message="InCheckCreditRequest"/>
                     <output message="OutCheckCreditResponse"/>
             </operation>

             <operation name="retrieveStockQuote">
                     <input message="InRetrieveStockQuote"/>
                     <output message="OutRetrieveStockQuote"/>
             </operation>

             <operation name="purchaseStock">
                     <input message="InPurchaseStockRequest"/>
                     <output message="OutPurchaseStockResponse"/>
             </operation>
          </portType>


The WSDL fragment above describes the public interface of our aggregate Web service. Since my composition is a Web service itself, I could actually leverage WSFL to recursively define yet another aggregate Web service which integrates our service with other Web services. I have shown that with just a few grammar rules, WSFL is a flexible XML language for defining Web services which are composed of other Web services.


Resources

About the author

Ajamu Wesley is a Senior Architect within IBM's Emerging Internet Technology division. Ajamu develops technical strategy, and architecture while providing technical consulting services promoting the adoption of leading edge technologies. His current role is technical lead for Federated Identity. Ajamu has generated several external technical publications with his latest project being the authorship of "Programming WebServices", which is an instructive book for programmers focusing on WebServices and related technologies. He can be reached at awesley@us.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=11641
ArticleTitle=WSFL: No Web service is an island
publish-date=02012002
author1-email=awesley@us.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers