Web Services Flow Language (WSFL 1.0)解説
2002年5月10日
富士通株式会社 プロジェクトA-XML XML応用技術部
 前田 隆之
1. WSFLの目的

WSFL (Web Services Flow Language)1.0は、2001年3月にIBMから提案された、複数のWebサービスをワークフローとして定義するためのXML言語です。WSFL1.0は、仕様書の冒頭で書かれているように、今後W3C (World Wide Web Consortium) 等の標準化団体に提案されるWebサービスワークフロー言語の原案となると思われますが、現時点では標準化されていません。それにも関わらず、WSFLはMicrosoftから提案されているXLANGと同様に、注目を集めています。

WSFLやXLANGが注目を集めている理由として、複数のWebサービスをプログラミングすることなく統合可能であることが挙げられます。そもそもWebサービスの目的として、「インターネット上で、プラットフォームやプログラミング言語に関わらず、アプリケーション統合を実現する手段を提供する」ことが挙げられます。WSFLにより、これらのWebサービスを組み合わせ、新たなWebサービスを実現することが可能になります。 WSFLは、ビジネスプロセスを記述するフローモデルと、Webサービスとの相互作用を記述するためのグローバルモデルの2つを定義します。また、以下のようなWSFLの特徴が仕様書に以記述されています。

fig1

fig2

2. WSFLの概要

WSFLについて詳細に説明する前に、WSFLがどのような場合に利用されるのかについて簡単に説明します。

図 3には、WSFL仕様の付録Dに記載されている,旅行予約の流れを示しています。この例では、旅行者(Traveler)が旅行代理店(Agent)に旅行を申し込むと、旅行代理店が申込に応じた飛行機の予約を航空会社(Airline)に対して行います。航空会社は座席の予約と、旅行者のクレジットカードによる決済を行ったあと、座席の確認を旅行代理店に送り、飛行機のチケットを旅行者に送ります。座席の確認を受け取った旅行代理店は、旅程を作成し旅行者に送付します。

まず、この例では旅行者、旅行代理店および航空会社という3つの役割が登場します。WSFLでは、これらの役割のことをサービスプロバイダと呼びます。

各サービスプロバイダは、外部に公開されたインタフェースを持ちます。WSFLでは、このサービスプロバイダが持つインタフェースの一覧をサービスプロバイダタイプと呼び、インタフェースの詳細は、WSDLの<portType>要素を用いて記述されます。図 3における旅行代理店は、旅行者に対するポートタイプと、航空会社に対するポートタイプという2種類のインタフェースを持ちます。旅行者に対するポートタイプには、旅行申込の受付と旅程の送付という2つのオペレーションが、航空会社に対するポートタイプには、チケットの申込と座席確認の受領という2つのオペレーションがそれぞれ定義されています。

また、この例では旅行代理店と航空会社の2つのビジネスプロセスが記述されています。WSFLでは、これらのビジネスプロセスをフローモデルにより記述します。ビジネスプロセスの各処理はアクティビティと呼ばれ、図 3では○印で記述されています。アクティビティは、各サービスプロバイダにより実装され、アクティビティの実装はWSDLのオペレーションとして記述されます。

フローモデルによるビジネスプロセスの記述とは別に、サービスプロバイダ間でメッセージがどのようにやり取りされるかを記述する必要があります。WSFLでは、この相互作用をグローバルモデルにより記述します。図 3では、点線の矢印で記述されています。

fig3

3. WSFLの構成

WSFLの構成を、図 3に示したチケットオーダの例に従って説明します。

WSFL文書の最上位要素は<definitions>要素です。この要素は以下の子要素を持ちます。

図 3の例を、WSFLにより記述したものを以下に示します。

<definitions name="totalTravelPortTypes"
targetNamespace="http://www.TravelLuck.com/WebServices/Messages/TotalTravel
xmlns:tio="http://www.TravelLuck.com/WebServices/Messages/TotalTravel"
xmlns="">
 チケットオーダに関する記述
</definitions>

3.1. 外部定義参照―<import>要素

外部にあるWSDL文書やWSFL文書を参照します。WSDLの<import>要素と同じ構成です。

3.2. サービスプロバイダのインタフェースの記述―<serviceProviderType>要素

サービスプロバイダが外部に公開するインタフェースの一覧を記述するには、<serviceProviderType>要素を用います。インタフェースの詳細は、この要素の子要素であるWSDLの<portType>要素により表現されます。

図 3では、以下に示すように航空会社、旅行代理店および旅行者の3つのサービスプロバイダタイプを宣言しています。

<serviceProviderType name="airlineFlow">
 <portType name="tio:ticketHandler"/>
 <portType name="tio:ticketDelivery"/>
</serviceProviderType>

<serviceProviderType name="agentFlow">
 <portType name="tio:tripHandler"/>
 <portType name="ticketRequester"/>
</serviceProviderType>

<serviceProvider name="travelerType">
 <portType name="tio:ticketBuyer"/>
</serviceProvider>

3.3. ビジネスプロセスの記述―<flowModel>要素

WSFLでは、図 3で述べた旅行代理店や航空会社のビジネスプロセスをフローモデルとして記述します。フローモデルの記述には、<flowModel>要素を用います。name属性によりフローモデルの名前を記述します。また、serviceProviderType属性は、このフローモデルの公開インタフェースを記述したサービスプロバイダタイプへの参照を表します。

フローモデルは、以下の子要素を持ちます。

図 3の旅行代理店におけるフローモデルを、WSFL仕様に記載された表記法に基づいて記述した例を図 4に示します。また、フローモデルをWSFLで記述すると以下のようになります。

<flowModel name="bookTrip" serviceProviderType="agentFlow">
 旅行代理店のビジネスプロセスに関する記述
</flowModel>

fig4

3.3.1. フローモデルへの入出力の記述―<flowSource>要素および<flowSink>要素

<flowSource>要素はフローモデルへの入力を、<flowSink>要素はフローモデルの出力を記述します。図 4における<flowSource>要素をWSFLで記述すると、以下のようになります。

<flowSource name="tripFlowSource">
 <output name="processInstanceData" message="tio:receivedTripOrder"/>
</flowSource>

3.3.2. サービスプロバイダに関する記述―<serviceProvider>要素

ビジネスプロセス内の各アクティビティを実行するサービスプロバイダは、<serviceProvider>要素により記述されます。図 4で示される旅行代理店のフローモデルでは、旅行者(traveler)と航空会社(airline)という2種類のサービスプロバイダを利用するため、以下の宣言をしています。

<serviceProvider name="airline" type="airlineFlow"/>
<serviceProvider name="traveler" type="travelerType"/>

この要素はname属性とtype属性の2つの属性を持ちます。name属性は、ビジネスプロセス内の各アクティビティから参照するために利用されます。また、type属性は、サービスプロバイダの公開インタフェースであるサービスプロバイダタイプを指定するために利用されます。

サービスプロバイダを実際の実装に結びつけるには、子要素である<locator>要素を利用します。この<locator>要素を、<flowModel>要素内の<serviceProvider>要素に記述することも可能ですが、図 3の例では<globalModel>要素内の<serviceProvider>要素に記述しています。このようにすることにより、ビジネスプロセスに関する記述からサービスプロバイダの実装に関する記述を分離することが可能になります。<locator>要素については、3.4.1を参照して下さい。

3.3.3. ライフサイクルに関する記述―<export>要素

lifecycleAction属性を持つ<export>要素は、フローモデルのライフサイクルに関するオペレーションを、フローモデルの公開インタフェースのオペレーションにエクスポートします。

以下に、図 4の旅行代理店における例を示します。ライフサイクルオペレーション"spawn"を、<target>子要素で指定した公開インタフェースのオペレーションにエクスポートしています。この宣言により、外部からポートタイプ"tio:tripHandler"のオペレーション"receiveTripOrder"にアクセスすると、フローモデルのインスタンスが生成されます。受け取ったメッセージは、<map>要素の記述に従い変換された後、3.3.1の<flowSource>要素で説明した、フローモデルの入力として利用されます。<map>要素については、3.3.6を参照して下さい。

<export lifecycleAction="spawn">
 <target portType="tio:tripHandler"
      operation="receiveTripOrder">
  <map sourceMessage="receiveTripOrderInput"
     targetMessage="processInstanceData"
     targetPart="request"/>
  <map sourceMessage="processInstanceData"
     sourcePart="agentWorkId"
     targetMessage="receiveTripOrderOutput"
     targetPart="agentWorkId"/>
 </target>
</export>

WSFL仕様は、以下のライフサイクルのオペレーションを定義しています。

3.3.4. アクティビティの記述―<activity>要素

ビジネスプロセスにおける各処理はアクティビティと呼ばれ、<activity>要素により記述されます。name属性には、アクティビティの名前を記述します。この名前は、制御リンクやデータリンクを記述する際に利用されます。

<activity>要素は以下の子要素を持ちます。

3.3.4.1. アクティビティの入出力メッセージの記述―<input>,要素、<output>要素および <fault>要素

アクティビティの入出力メッセージは、<input>要素と<output>要素によりそれぞれ記述されます。また、このアクティビティが出力するエラーメッセージは、<fault>要素により記述されます。

3.3.4.2. アクティビティの実装に関する記述―<performedBy>要素および<implement>要素

このアクティビティを実行するサービスプロバイダを指定する場合には、<performedBy>要素を利用します。この要素のserviceProvider属性値に3.3.2で記述したサービスプロバイダ名を指定します。

アクティビティの実装は、<implement>要素を用いて記述されます。アクティビティを特定の実装に結びつけるには、アクティビティのオペレーションと、その実装のオペレーションを3.4.2で説明する<plugLink>要素で結びつけることで実現されます。このようにすることにより、アクティビティの実装としてWebサービスを利用することが可能になります。

アクティビティの実装が内部に存在する場合には、<internal>要素の下に直接<plugLink>要素を記述します。このようにすることにより、内部のアクティビティのオペレーションは、フローモデルの外部から隠蔽されます。図 4において、どの飛行機を予約するかを決定するアクティビティの実装は内部に存在するため、以下のような記述になります。

<activity name="selectLegs">
 <input name="dataIn" message="tio:receivedTripOrder"/>
 <output name="dataOut" message="tio:tripRecord"/>
 <performedBy serviceProvider="local"/>
 <implement>
  <internal serviceProviderType=... portType=... operation=...>
   <plugLink>
    <source serviceProviderType=... portType=... operation=... />
    <target serviceProviderType=... portType=... operation=... />
   </plugLink>
  </internal>
 </implement>
</activity>

一方で、アクティビティの実装が外部のWebサービスである場合、<export>要素を用いて、アクティビティのオペレーションをフローモデルの公開インタフェースにエクスポートします。アクティビティのオペレーションと、外部Webサービスのオペレーション間の相互作用はフローモデルの公開インタフェースを介して行われ、<plugLink>要素はグローバルモデルに記述されます。図 4において、航空会社に対してチケットの申込をするアクティビティの記述を以下に示します。

<activity name="orderTickets">
 <input name="orderTicketsInput" message="tio:tripRecord"/>
 <output name="orderTicketsOutput" message="tio:sentTicketOrder"/>
 <performedBy serviceProvider="airline"/>
 <implement>
  <export portType="tio:ticketRequester"
       operation="requestTicketOrder">
   <map sourceMessage="OrderTicketsInput"
      sourcePart="ourTicketorder"
      targetMessage="requestTicketOrderOutput"/>
   <map sourceMessage="requestTicketOrderInput"
      sourcePart="theAirlineWorkId"
      targetMessage="orderticketsOutput"
      targetPart="theAirlineWorkId"/>
  </export>
 </implement>
</activity>

3.3.5. 制御の流れの記述―<controlLink>要素

ビジネスプロセス内のアクティビティの実行順序は、<controlLink>要素を用いて記述されます。source属性で指定したアクティビティの実行が完了すると、その次にtarget属性で指定したアクティビティが実行されます。 図 4の旅行代理店における制御リンクの例を以下に示します。

<controlLink name="sL-oT"
        source="selectLegs"
        target="orderTickets"/>

3.3.6. データの流れの記述―<dataLink>要素

アクティビティ間のデータのやり取りは、<dataLink>要素を用いて記述します。source属性で指定したアクティビティの出力が、target属性で指定したアクティビティの入力として渡されます。<map>要素を用いることで、データのマッピングや変換を行うことが可能です。

以下に、図 4の旅行代理店における例を示します。下記例では、"orderTickets"アクティビティの出力を"getConfirmation"アクティビティの入力として渡す記述を示しています。<map>要素を利用することで、"orderTicketsOutput"メッセージの"orderRecord"というパートを、"getConfirmationInput"メッセージの"orderRecord"というパートにマッピングしています。<map>要素には、このようなマッピングの他に、XSLT等による変換を行うconverter属性を指定することも可能です。

<dataLink name="oT-rCdata"
      source="orderTickets"
      target="getConfirmation"
 <map sourceMessage="orderTicketsOutput"
    sourcePart="orderRecord"
    targetMessage="getConfirmationInput"
    targetPart="orderRecord"/>
</dataLink>

3.3.7. 複雑なフローの記述

図 4に示す旅行代理店のビジネスプロセスは、あるアクティビティの実行が完了すると、制御とデータが次のアクティビティに遷移するという単純なフローでした。しかし、WSFLでは1つのアクティビティに対して複数の制御リンクやデータリンクを持つことが可能です。以下では、これらを制御する方法について簡単に説明します。

3.3.7.1. 遷移条件

まず、分岐について説明します。分岐は、あるアクティビティを起点とする<controlLink>要素を複数記述することで実現されます。図 5のアクティビティAがこのアクティビティに当たります。

<controlLink>要素に遷移条件を記述することで、条件分岐を表現することも可能です。遷移条件は、<controlLink>要素のtransitionCondition属性に、アクティビティの出力値に対する論理式を記述することで実現されます。この論理式には、XPath式を利用します。論理式が真となった場合、次のアクティビティに処理が移ります。図 5を例にとると、アクティビティAの実行完了後、遷移条件pABが真になると、アクティビティBが実行されます。しかし、遷移条件pABが偽の場合、アクティビティBは実行されません。

また、transitionCondition属性で論理式を指定する代わりに、result属性により、アクティビティの出力するメッセージそのものを指定することも可能です。これは、主にアクティビティがエラーメッセージを出力した場合のエラー処理に利用されます。

fig5

3.3.7.2. 結合条件

次に、結合について説明します。分岐により並列に実行している処理は、結合アクティビティと呼ばれるアクティビティで結合します。図 5のアクティビティEが結合アクティビティに当たります。結合条件は、結合アクティビティの子要素である<join>要素のcondition属性に、制御リンクの遷移条件に対する論理式を記述することで実現されます。例えば、図 5のアクティビティEの結合条件にpDEかつpCEと指定した場合、どちらか一方、あるいはその前の遷移条件が偽になるとアクティビティEは実行されません。

また、when属性にdeferredを指定すると、結合条件が真に確定した場合でも、すべての制御リンクの遷移条件が確定するまで待機します。

3.3.7.3. 終了条件

アクティビティの終了条件は、終了条件が記述されたアクティビティ、またはその前に実行されたアクティビティの入出力値に対する論理式で表現され、<activity>要素のexitCondition属性値として記述されます。終了条件が真の場合、アクティビティの実行は完了します。終了条件が偽の場合、再びこのアクティビティが実行されます。この終了条件は、何らかの理由で実行が失敗した場合のリトライや、ループを実現するために利用されます。

WSFLでは、図 6に示すA→B→D→Aのような巡回グラフをサポートしていません。しかし、図 1に示すように、アクティビティをcallライフサイクルオペレーションでインスタンス化される他のフローにより実装し、それをアクティビティの終了条件と組み合わせることによりdo-untilループを実現することが可能です。このループにより、動的に不特定数のWebサービスを呼び出すことが可能になります。

fig6

3.3.7.4. 複数のデータリンクによる入力の生成

図 3の旅行代理店のビジネスプロセスは、データフローについても制御に従って流れるだけの単純なものでした。しかし、実際にはあるアクティビティの入力として複数のデータリンクが接続され、それらの間で衝突が発生する可能性も考えられます。これを回避するために、<activity>要素は<materialize>要素を子要素として持つことが可能です。

<materialize>要素は、<mapPolicy>要素と<construction>要素の2種類の子要素を持つことが可能です。

<mapPolicy>要素は、order属性により複数の入力の中からどのデータを採用するかを記述します。order属性は以下の値のいずれかを取ります。

一方で、<construction>要素は、入力データの生成方法を記述します。この要素は、type属性でXSLTを初期値とする生成方法を指定し、location属性で変換に利用するファイルを指定します。

3.4. グローバルモデルの記述―<globalModel>要素

グローバルモデルでは、サービスプロバイダ間またはサービスプロバイダ間の相互作用を記述します。これを実現するために、<globalModel>要素には以下の子要素が存在します。

また、グローバルモデルに対して、新たなサービスプロバイダタイプを定義し、フローモデルや他のグローバルモデルを統合したWebサービスの作成に利用することも可能です。図 3の例では、図 7に示すように、旅行代理店と航空会社のフローモデルを統合したサービスプロバイダタイプ"agentNAirlineFlow"を宣言して、新たなWebサービスを作成しています。

図 7に対応するグローバルモデルを含んだWSFLの定義を以下に示します。

<definitions name="totalTravelPortTypes"
 targetNamespace="http://www.TravelLuck.com/WebServices/Messages/TotalTravel"
 xmlns:tio="http://www.TravelLuck.com/WebServices/Messages/TotalTravel"
 xmlns="">
 <serviceProviderType name="agentNAirlineFlow">
  <portType name="tio:tripNTicketHandler">
 </serviceProviderType>

 <globalModel name="bookTripNTickets"
         serviceproviderType="agentNAirlineFlow">
  グローバルモデルに関する記述
 </globalModel>
</definitions>

fig7

3.4.1. サービスプロバイダの記述―<serviceProvider>要素

グローバルモデル内に出現する<serviceProvider>要素には、以下の子要素が出現します。

3.4.1.1. 実装へのバインディング―<locator>要素

<serviceProvider>要素の子要素として出現した<locator>要素は、フローモデルの各アクティビティを実行するサービスプロバイダを、特定の実装にバインドするために利用されます。この要素のtype属性は、実装へのバインドの種類を示します。その他の属性や子要素は、このtype属性の値により変化します。

type属性として、以下の値を指定することが可能です。

3.4.1.2. オペレーションのエクスポート―<export>要素

<serviceProvider>要素の子要素として出現する<export>要素は、そのサービスプロバイダのオペレーションを、グローバルモデルの公開インタフェースとしてエクスポートするために利用します。

3.4.1.3. <serviceProvider>要素の例

図 3における旅行代理店の例を以下に示します。<export>要素により、旅行代理店のオペレーションを、3.4で新たに定義したグローバルモデルの公開インタフェースであるサービスプロバイダタイプにエクスポートしています。また、<locator>要素により、旅行代理店という役割を持つサービスプロバイダをTraveluck.comという実際のサービスに静的に結びつけています。

<serviceProvider name="travelAgent" serviceProviderType="tio:agentFlow">
 <export>
  <source portType="tio:tripHandler" operation="sendItinerary"/>
  <target portType="tio:tripNTicketHandler" operation="sendItinerary"/>
 </export>
 <export>
  <source portType="tio:tripHandler" operation="receiveTripOrder"/>
  <target portType="tio:tripNTicketHandler" operation="receiveTripOrder"/>
 </export>
 <locator type="static" service="Traveluck.com"/>
</serviceProvider>

3.4.2. オペレーション間の結びつけ―<plugLink>要素

<plugLink>要素は、サービスプロバイダ間、サービスプロバイダタイプ間またはその両者の間の相互作用を記述します。以下に図 3のグローバルモデルにおける<plugLink>要素の例を示します。この例では、子要素である<source>要素で指定した航空会社の"sendConfirmation"というオペレーションと、子要素である<target>要素で指定した旅行代理店の"waitForConfirmation"というオペレーションを結びつけています。実行時にはこのオペレーション間でメッセージがやり取りされます。

<plugLink>
 <source serviceProvider="airline"
      portType="tio:ticketHandler"
      operation="sendConfirmation"/>
 <target serviceProvider="travelAgent"
      portType="tio:tripHandler"
      operation="waitForConfirmation"/>
</plugLink>
<plugLink>要素には、<source>要素と<target>要素の他に、3.3.6で説明した<map>要素や、3.4.1.1で説明した<locator>要素を含めることも可能です。<map>要素は、オペレーションでやり取りされるメッセージのマッピングや変換を行います。また、<locator>要素は"mobility"タイプに限られ、指定したオペレーションのメッセージを用いて、実行時にターゲットのエンドポイントアドレスを決定します。

4. 関連仕様
4.1. Web Services Endpoint Language (WSEL)

Webサービスが提供する機能は、WSDLにより記述されます。このWSDLを参照することにより、データの型や利用するプロトコル、エンドポイントのアドレスが分かります。しかし、このWebサービスを実際にビジネスで利用するには、機能以外の様々な情報が必要になります。例えば、それは実行にかかる費用であったり、最大接続時間であったり、セキュリティに関する情報であったりします。このような、Webサービスが提供する機能とは異なる、エンドポイントに関するプロパティを、エンドポイントプロパティと呼びます。

このエンドポイントプロパティを記述する言語として、Web Services Endpoint Language (WSEL) がWSFL仕様に記述されています。WSFLでは、<locator>要素により動的にサービスプロバイダを決定することが可能です。このサービスプロバイダの候補が複数ある場合、最も適切なサービスプロバイダを選択するためにWSELが利用されます。このWSELは、フローモデル内のアクティビティの内部と、Webサービスの機能を記述するWSDLとの両側に記述され、両者のWSELをつき合わせることで最適なサービスを選択します。

この仕様は、現在IBMにより策定中であり、エンドポイントプロパティを記述するためのフレームワークと、基本的なプロパティのみを定義するようです。

4.2. Web Services Conversation Language (WSCL) 1.0

WSFLにおけるサービスプロバイダタイプは、サービスを提供するサービスプロバイダが実装しなければならないインタフェースの一覧を表しています。例えば、図 3の航空会社の実装者は、旅行代理店に対して図 8に示すように、チケット申込受付と座席確認送付という2つのオペレーションを実装する必要があります。

これら2つのオペレーションは、図 9に示すように必ずチケットの申込受付の後に、座席確認の送付という順序で実行されなければなりません。しかし、WSFLのサービスプロバイダタイプやWSDLのインタフェース定義では、この順序に関する制約条件を記述することはできません。B2Bの世界では、RosettaNetのPIPで記述されるように、メッセージがやり取りされる順序が重要となります。そのため、WSFLをB2Bで利用するには、このメッセージをやり取りする順序を規定する機構が必要となります。

fig8

fig9

これを実現する仕様として、Hewlett-PackardはWeb Services Conversation Language (WSCL) をW3Cにノートとして提案しています。WSCLは、2つのサービスプロバイダ間でやり取りされるメッセージやオペレーションの順序を記述するための仕様です。WSCLを用いてRosettaNetのPIPを記述したり、WSCLで記述した定義をUDDIのtModelとして登録したりすることが可能です。なお、3つ以上のサービスプロバイダ間でのやり取りや、トランザクションといった複雑な項目については、今後拡張されていくようです。

図 8で示した、航空会社の旅行代理店に対するオペレーションの実行順序を、WSCLを用いて定義した例を以下に示します。<transition>要素により、オペレーションの順序を規定しています。

<?xml version="1.0" encoding="UTF-8"?>
<Conversation name="TicketHandlerConversation"
   xmlns="http://www.w3.org/2002/02/wscl10"
xmlns:tio="http://www.TraveLuck.com/WebServices/Messages/TotalTravel"
   initialInteraction="tio:receiveTicketOrder"
   finalInteraction="tio:sendConfirmation">

 <ConversationTransitions>
  <Transition>
   <SourceInteraction href="tio:receiveTicketOrder"/>
   <DesticationInteraction href="tio:sendConfirmation"/>
  </Transition>
 </ConversationTransitions>
</Conversation>

5. おわりに

以上述べてきたWSFLを利用することで、ビジネスプロセスの一部として複数のWebサービスを静的あるいは動的に組み込み、新たなWebサービスを定義することが可能になります。また、ローカルにあるソフトウェアコンポーネントもプロセスに組み込むことが可能であるため、既存の資産を生かしつつ外部のWebサービスを組み込むことで拡張していくことが可能です。今後Webサービスが世の中に広まり、WSFLに対する開発環境や実行環境が出揃うことにより、WSFLはますます重要な技術となっていくと思われます。