ヘッダーをスキップ
Oracle® Fusion Middleware Oracle WebLogic Server JAX-RPC Webサービスの高度な機能のプログラミング
11g リリース1 (10.3.6)
B61634-05
  ドキュメント・ライブラリへ移動
ライブラリ
製品リストへ移動
製品
目次へ移動
目次

前
 
次
 

4 会話型Webサービスの作成

この章では、会話型のWebLogic Java API for XML-based RPC (JAX-RPC) Webサービスの作成方法について説明します。

この章では、以下のトピックについて説明します。

会話型Webサービスの概要

Webサービスと、そのWebサービスを呼び出すクライアント・アプリケーションは、1つのタスクを完了するために複数回通信する場合があります。また、複数のクライアント・アプリケーションが同時に同じWebサービスと通信する場合もあります。会話を使用すると、直接的な方法で、呼出し間のデータを追跡して、Webサービスが常に正しいクライアントに応答するようにできます。

会話を使用すると、複数の通信にわたってデータを維持することに伴う以下の2つの問題が解決されます。

WebLogic Serverはこの一意のIDと状態を、クライアント・アプリケーションが新しく会話を開始するたびに会話コンテキストを作成することによって管理します。Webサービスがその後、このコンテキストを使用して、サービスとの間の呼出しを相関させ、状態関連データを永続化します。

クライアント・アプリケーションとWebサービスの間の会話には、3つの異なるフェーズがあります。

会話は通常、2つのWebLogic Webサービス間で発生します。そのうち1つは会話型としてマークされ、開始、続行、および終了の操作を定義し、もう1つのWebサービスは@ServiceClientアノテーションを使用して、それが会話型Webサービスのクライアントであることを指定します。また、制限事項はありますが、会話型WebサービスはスタンドアロンJavaクライアントからも呼び出せます。

他のWebLogic Webサービスの機能と同様に、Webサービスを会話型のものとして指定するには、JWSアノテーションを使用します。


注意:

会話型Webサービスを呼び出すクライアントWebサービスは、必ずしも会話型にする必要はありません。ただし、クライアントが会話型でない場合は、このクライアントの複数のインスタンスが同じ会話型Webサービス・スタブにアクセスする危険性があり、保存されている会話状態が破損するおそれがあります。この危険性があると判断した場合は、クライアントWebサービスも会話型になるように指定してください。その場合は、スタンドアロンのJavaクライアントは使用できません。これは、WebLogic APIを使用して会話型であることを指定する方法がないためです。

会話型Webサービス自体は、必ず1回、メッセージの配信が行われることや、メッセージが順序どおりに配信されることを保証するものではありません。そのようなメッセージ配信保証が必要であれば、Webサービスに信頼性があることも指定する必要があります。「Webサービスの信頼性のあるメッセージングの使用: 主な手順」および「非同期機能の併用」を参照してください。


会話型Webサービスの作成: 主な手順

次の手順では、会話型Webサービス、ならびにクライアントWebサービスおよびスタンドアロンJavaクライアント・アプリケーション(いずれも会話を開始および実施するもの)を作成する方法について説明します。この手順では、2つのWebサービスを実装するJWSファイルをゼロから作成する方法を示しています。既存のJWSファイルを更新する場合は、この手順をガイドとして利用することもできます。

Antベースの開発環境を設定済であり、かつjwsc Antタスクを実行して生成された会話型Webサービスをデプロイするためのターゲットを追加できる、作業用のbuild.xmlファイルがあることが前提となっています。さらに、会話を開始するクライアントWebサービスをホストする、WebLogic Serverインスタンスを同様に設定してあることも前提となっています。詳細は、『Oracle WebLogic Server JAX-RPC Webサービス・スタート・ガイド』の次の項を参照してください。

表4-1 会話型Webサービスの作成手順

#
手順 説明

1

会話型Webサービスを実装する、新しいJWSファイルを作成するか、既存のJWSファイルを更新します。

使い慣れたIDEまたはテキスト・エディタを使用します。「会話型JWSファイルに関するプログラミングのガイドライン」を参照してください。

2

build.xmlファイルを更新して、会話型JWSファイルをWebサービスにコンパイルするjwsc Antタスクの呼出しを含めます。

『Oracle WebLogic Server JAX-RPC Webサービス・スタート・ガイド』のjwsc WebLogic WebサービスAntタスクの実行に関する項を参照してください。

3

Antターゲットを実行して、会話型Webサービスをビルドします。

例:

prompt> ant build-mainService

4

ターゲットWebサービスを通常どおりデプロイします。

『Oracle WebLogic Server JAX-RPC Webサービス・スタート・ガイド』のWebLogic Webサービスのデプロイとアンデプロイに関する項を参照してください。

5

クライアントWebサービスを実装する、新しいJWSファイルを作成するか、既存のJWSファイルを更新します。

クライアント・アプリケーションがスタンドアロンJavaクライアントである場合は、「会話型Webサービスを呼び出すためのスタンドアロンJavaクライアントの更新」を参照してください。ステップ6 - 9をスキップします。

クライアント・アプリケーション自体がWebサービスである場合は、ステップ6 - 9に従います。

6

会話型Webサービスで会話を開始および実施する新しいJWSファイルを作成するか、既存のJWSファイルを更新します。

使い慣れたIDEまたはテキスト・エディタを使用します。クライアントWebサービスが、会話型Webサービスをホストするものとは別のWebLogic Serverインスタンスにデプロイされていることが前提となります。「会話型Webサービスを呼び出すJWSファイルに関するプログラミングのガイドライン」を参照してください。

7

クライアントWebサービスをビルドするbuild.xmlファイルを更新します。

「会話型Webサービスのクライアント用build.xmlファイルの更新」を参照してください。

8

Antターゲットを実行して、クライアントWebサービスをビルドします。

例:

prompt> ant build-clientService

9

クライアントWebサービスを通常どおりデプロイします。

『Oracle WebLogic Server JAX-RPC Webサービス・スタート・ガイド』のWebLogic Webサービスのデプロイとアンデプロイに関する項を参照してください。


会話型JWSファイルに関するプログラミングのガイドライン

次のサンプルでは、会話型Webサービスを実装する簡単なJWSファイルを示します。太字で示されたJavaコードに対応するコーディングのガイドラインについては、サンプルの後の説明を参照してください。

package examples.webservices.conversation;

import java.io.Serializable; 

import weblogic.jws.WLHttpTransport;
import weblogic.jws.Conversation; 
import weblogic.jws.Conversational; 
import weblogic.jws.Context; 
import weblogic.wsee.jws.JwsContext; 
import weblogic.wsee.jws.ServiceHandle; 

import javax.jws.WebService;
import javax.jws.WebMethod;
@Conversational(maxIdleTime="10 minutes", 
                maxAge="1 day", 
                runAsStartUser=false, 
                singlePrincipal=false ) 
@WebService(name="ConversationalPortType",
            serviceName="ConversationalService",
            targetNamespace="http://examples.org/")

@WLHttpTransport(contextPath="conv",
                 serviceUri="ConversationalService",
                 portName="ConversationalServicePort")

/**
 * Conversational Web service.
 */

public class ConversationalServiceImpl implements Serializable { 

  @Context 
  private JwsContext ctx; 
  public String status = "undefined"; 

  @WebMethod
  @Conversation (Conversation.Phase.START) 
  public String start() {

    ServiceHandle handle = ctx.getService(); 
    String convID = handle.getConversationID(); 

    status = "start";
    return "Starting conversation, with ID " + convID + " and status equal to " + status;

  }

  @WebMethod
  @Conversation (Conversation.Phase.CONTINUE) 
  public String middle(String message) {

    status = "middle";
    return "Middle of conversation; the message is: " + message + " and status is " + status;

  }

  @WebMethod
  @Conversation (Conversation.Phase.FINISH) 
  public String finish(String message ) {

    status = "finish";
    return "End of conversation; the message is: " + message + " and status is " + status;

  }

}

会話型Webサービスを実装するJWSファイルをプログラミングする際には、次のガイドラインに従います。ガイドラインのコード・スニペットは、前述のサンプルでは太字で示されています。

会話型Webサービスを呼び出すJWSファイルに関するプログラミングのガイドライン

次の例では、「会話型JWSファイルに関するプログラミングのガイドライン」で説明した会話型Webサービスを呼び出すWebサービス用の簡単なJWSファイルを示します。太字で示されたJavaコードに対応するコーディングのガイドラインについては、サンプルの後の説明を参照してください。

package examples.webservices.conversation;

import weblogic.jws.WLHttpTransport;
import weblogic.jws.ServiceClient; 

import weblogic.wsee.conversation.ConversationUtils; 

import javax.jws.WebService;
import javax.jws.WebMethod;

import javax.xml.rpc.Stub;

import examples.webservices.conversation.ConversationalPortType; 

import java.rmi.RemoteException;

@WebService(name="ConversationalClientPortType",
            serviceName="ConversationalClientService",
            targetNamespace="http://examples.org/")

@WLHttpTransport(contextPath="convClient",
                 serviceUri="ConversationalClient",
                 portName="ConversationalClientPort")

/**
 *  client that has a conversation with the ConversationalService.
 */

public class ConversationalClientImpl {

  @ServiceClient( 
     wsdlLocation="http://localhost:7001/conv/ConversationalService?WSDL", 
     serviceName="ConversationalService", 
     portName="ConversationalServicePort") 
 
  private ConversationalPortType port; 

  @WebMethod
  public void runConversation(String message) {

    try {

      // Invoke start operation
      String result = port.start(); 
      System.out.println("start method executed.");
      System.out.println("The message is: " + result);

      // Invoke continue operation
      result = port.middle(message ); 
      System.out.println("middle method executed.");
      System.out.println("The message is: " + result);

      // Invoke finish operation
      result = port.finish(message ); 
      System.out.println("finish method executed.");
      System.out.println("The message is: " + result);
      ConversationUtils.renewStub((Stub)port); 

    }
    catch (RemoteException e) {
      e.printStackTrace();
    }

  }

}

会話型Webサービスを呼び出すJWSファイルをプログラミングする際には、次のガイドラインに従います。ガイドラインのコード・スニペットは、前述のサンプルでは太字で示されています。

ConversationUtilsユーティリティ・クラス

WebLogic Serverには、会話機能で使用するユーティリティ・クラスが用意されています。このクラスを使用すると、会話IDの取得や設定、構成オプションの設定といった一般的なタスクを実行できます。これらのタスクには、会話型Webサービス内で実行するものと、会話型Webサービスを呼び出すクライアント内で実行するものがあります。このクラスの使用例については、「会話型Webサービスを呼び出すJWSファイルに関するプログラミングのガイドライン」を参照してください。

詳細は、Oracle WebLogic Server APIリファレンスweblogic.wsee.conversation.ConversationUtilsに関する項を参照してください。

会話型Webサービスのクライアント用build.xmlファイルの更新

build.xmlファイルを更新して、会話型Webサービスを呼び出すJWSファイルを生成するには、次のサンプルのようなtaskdefsおよびbuild-clientServiceターゲットを追加します。詳細は、サンプルの後の説明を参照してください。

<taskdef name="jwsc"
    classname="weblogic.wsee.tools.anttasks.JwscTask" />

  <target name="build-clientService">

    <jwsc
        enableAsyncService="true"
        srcdir="src"
        destdir="${clientService-ear-dir}" >

        <jws file="examples/webservices/conversation/ConversationalClientImpl.java" >
          <clientgen 
            wsdl="http://${wls.hostname}:${wls.port}/conv/ConversationalService?WSDL" 
            packageName="examples.webservices.conversation"/> 

        </jws>

    </jwsc>

  </target>

jwsc Antタスクの完全なクラス名を定義するには、taskdef Antタスクを使用します。

クライアントWebサービスをコンパイルするjwsc Antタスクを更新して、<jws>要素の<clientgen>子要素を含めます。これにより、デプロイされたConversationalService WebサービスのJAX-RPCスタブが生成およびコンパイルされるようになります。jwsc Antタスクでは、これらのスタブが生成されたWARファイルに自動的にパッケージ化されるため、即座にクライアントWebサービスからアクセスできるようになります。このようにするのは、生成されたクラスの1つをConversationalClientImpl JWSファイルでインポートして使用するためです。

会話型Webサービスを呼び出すためのスタンドアロンJavaクライアントの更新

次の例では、「会話型JWSファイルに関するプログラミングのガイドライン」で説明した会話型Webサービスを呼び出す、簡単なスタンドアロンのJavaクライアントを示します。太字で示されたJavaコードに対応するコーディングのガイドラインについては、サンプルの後の説明を参照してください。

package examples.webservices.conv_standalone.client;

import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;
import javax.xml.rpc.Stub;
import weblogic.wsee.jaxrpc.WLStub; 

/**
 * stand-alone client that invokes and converses with ConversationlService.
 */

public class Main {

  public static void main(String[] args)
      throws ServiceException, RemoteException{

      ConversationalService service = new ConversationalService_Impl(args[0] + "?WSDL");
      ConversationalPortType port = service.getConversationalServicePort();

      // Set property on stub to specify that client is invoking a Web service
      // that uses advanced features; this property is automatically set if
      // the client runs in a WebLogic Server instance.

      Stub stub = (Stub)port; 
      stub._setProperty(WLStub.COMPLEX,  "true"); 

      // Invoke start operation to begin the conversation
      String result = port.start(); 
      System.out.println("start method executed.");
      System.out.println("The message is: " + result);

      // Invoke continue operation
      result = port.middle("middle" ); 
      System.out.println("middle method executed.");
      System.out.println("The message is: " + result);

      // Invoke finish operation
      result = port.finish("finish" ); 
      System.out.println("finish method executed.");
      System.out.println("The message is: " + result);

  }

}

会話型Webサービスを呼び出すスタンドアロンJavaクライアントをプログラミングする際には、次のガイドラインに従います。ガイドラインのコード・スニペットは、前述のサンプルでは太字で示されています。

会話型Webサービスの.NETクライアントの例

この項では、会話型WebLogic Webサービスの.NET WSE3.0クライアントを作成する方法について説明します。この例には次のファイルが含まれています。

これらのファイルについては、以降の項で詳しく説明します。

ConversationService.javaファイル

サンプルのConversationService.javaファイルを例4-1に示します。このサンプルには、機能を説明するコメントが大量に含まれています。

例4-1 ConversationService.javaファイル

package conv;
 
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.Oneway;
 
import weblogic.jws.Conversation;
import weblogic.jws.Callback;
import weblogic.jws.CallbackService;
 
import java.io.Serializable;
 
/**
 * Demonstrates use of the @Conversation annotation to manage the lifetime of the service
 * and provide data persistence and message correlation.
 * 
 * Remember that multiple clients might invoke a web service simultaneously.  When the
 * web service stores data relevant to the client or calls additional services
 * in order to process a client's request, the service must be able to process returned
 * data from the external services in the context of the specific client it relates
 * to.  This is all automatic when conversations are used.
 * 
 * Remember that not all clients are capable of accepting callbacks.  Specifically,
 * clients operating from behind firewalls may not be able to receive asynchronous
 * callbacks.  You may wish to provide a synchronous interface, like this one,
 * for such clients.  If a client can accept callbacks, it must send a callback endpoint refrence
 * as part of any "start conversation" method invocation.
 * 
 * To see the behavior in the Test View, invoke startRequest and then getRequestStatus
 * several times quickly.
 */
@WebService(serviceName = "ConversationService", portName = "conversation", targetNamespace = "http://www.openuri.org/")
public class ConversationService implements Serializable {
 
  @Callback
  public CallbackInterface callback;
  private boolean useCallbacks;
  private int num;
 
  /**
   * Starts the conversation
   */
  @Conversation(Conversation.Phase.START)
  @WebMethod
  public void startRequest(boolean useCallbacks) {
    this.useCallbacks = useCallbacks;
  }
 
  @WebMethod
  @Conversation(Conversation.Phase.CONTINUE)
  public String getRequestStatus() {
 
    num++;
    if (num == 1)
      return "This is the first time you call getRequestStatus method.";
    if (num == 2 && useCallbacks) {
      callback.onResultReady("finished");
      return "This is the second time you call  getRequestStatus method, the conversation has been terminated automtically when the onResultReady callback method is invoked.";
    } else
      return "You have called getRequestStatus method " + num + " times";
 
  }
 
  /**
   * Used to tell Conversation.jws that the current conversation is
   * no longer needed.
   */
  @WebMethod
  @Conversation(Conversation.Phase.FINISH)
  public void terminateRequest() {
 
  }
 
  @CallbackService(serviceName = "ConversationCallbackService")
  public interface CallbackInterface {
 
    /**
     * Callback to invoke on the client when the external service
     * returns its result. Will only be called it the client can
     * accept callbacks and told us where to send them.
     * <p/>
     * If this callback is used, it implicitly terminates the
     * conversation with no action required on the part of the
     * client.
     */
    @WebMethod
    @Oneway
    @Conversation(Conversation.Phase.FINISH)
    public void onResultReady(String result);
  }
 
}

Service.csファイル

サンプルのService.csファイルを例4-2に示します。

この会話プロキシ・ファイルは、Microsoft WSDL to Proxy ClassツールWseWsdl3.exe(http://msdn.microsoft.com/en-us/library/aa529578.aspxを参照)とConversationService WebサービスのWSDLファイルを使用して作成したものです。

このサンプルには、機能を説明するコメントが大量に含まれています。

例4-2 Service.csファイル

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Diagnostics;
using System.IO;
using System.Xml;
using Microsoft.Web.Services3.Addressing;
using Microsoft.Web.Services3;
using System.Collections.Generic;
using Microsoft.Web.Services3.Design;
 
 
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    
    public Service () {
 
        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }
 
    /*
    * start invokes the Conversation web service's startRequest
    * operation.
    * 
    * Since the Conversation web service is conversational,
    * we must also persist the ReplyTo endpoint reference SOAP header
    * for subsequent calls.
    * 
    * Since the Conversation web service can optionally communicate
    * the result of it's work via a callback, we must prepare a
    * second SOAP header CallbackTo SOAP header, which is the endpoint reference 
    * of the recipient to which callbacks should be sent.
    */
    [WebMethod(EnableSession = true)]
    public void start(Boolean useCallbacks, Boolean useIPAddress)
    {
        /*
         * The Conversation proxy was created using .NET WSE3.0's WseWsdl3.exe
         * application and the Conversation.jws's WSDL file.  The WSDL
         * file for any WLS web service may be obtained
         * by hitting the web service's URL with "?WSDL" appended to
         * the end.  For example:
         * 
         * http://somehost:7001/samples/async/Conversation.jws?WSDL
         * 
         * WseWsdl3.exe produces a C# proxy class.  Place the resulting
         * ConversationService.cs file in your .NET project, then use Visual
         * Studio's Project->Add Existing Item menu action to "import"
         * the class into the project.
         */
        ConversationServiceSoapBinding conv;
        String callbackLocation;
        int asmxIndex;
 
        /*
         * Construct the callback URL from various pieces of
         * server and HttpRequest info.
         */
        Uri requestUrl = Context.Request.Url;
 
        if (useIPAddress)
        {
            /*
             * if useIPAddress is true, construct the callback address
             * with the IP address of this host.
             */
            callbackLocation = requestUrl.Scheme + "://" + System.Net.Dns.GetHostByName(requestUrl.Host).AddressList[0] +
                ":" + requestUrl.Port + requestUrl.AbsolutePath;
        }
        else
        {
            /*
             * if useIPAddress is false, construct the callback address
             * with the hostname of this host.
             */
            callbackLocation = requestUrl.Scheme + "://" + requestUrl.Host +
                ":" + requestUrl.Port + requestUrl.AbsolutePath;
        }
 
        // Remove everything after ".asmx"
        asmxIndex = callbackLocation.IndexOf(".asmx") + 5;
        callbackLocation = callbackLocation.Remove(asmxIndex,
                                 callbackLocation.Length - asmxIndex);
 
        /*
         * Create an instance of the proxy for the Conversation
         * web service.
         * 
         */
        conv = new ConversationServiceSoapBinding();
 
        
        /*
         * When callback is enabled, a custom callback header should be added into 
         * the outbound soap message. 
         * 
         */
        if (useCallbacks)
            enableSoapFilterToAddCallbackHeader(conv, callbackLocation);
        
    
        /*
         * Invoke the startRequest method of the web service. The
         * single boolean parameter determines whether the Conversation
         * web service will use callbacks to communicate the result
         * back to this client.
         * 
         * If the argument is true, an onResultReady callback will
         * be sent when the result is ready.  This client must implement
         * a method with that name that expects the message shape defined
         * by the target web service (returns void and accepts a single
         * string argument).  See the onResultReady method below.
         * 
         * If the argument to startRequest is false, callbacks will not
         * be used and this client must use the getRequestStatus method
         * to poll the Conversation web service for the result.
         */
        conv.startRequest(useCallbacks);
        /*
         * Persist the ReplyTo header  in session state so that it can
         * be used in other methods that take part in the conversation.
         * 
         * This is not safe since one session could start multiple
         * conversations, but there is no other apparent way to persist
         * this information.  Member variables of WebService classes
         * are not persisted across method invocations.
         */
        Session["ConversationReplyTo"] = conv.ResponseSoapContext.Addressing.ReplyTo;
 
 
    }
 
    /* the CallbackTo header defintion isn't exposed by WLS9x/WLS10x callback service. 
     * So we need to use SOAPFilter to add the CallbackTo header. 
     * 
     */
    private static void enableSoapFilterToAddCallbackHeader(ConversationServiceSoapBinding conv, String callbackLocation)
    {
        //Create a custom policy.
        Policy myPolicy = new Policy();
        // Create a new policy assertion
        MyPolicyAssertion myAssertion = new MyPolicyAssertion(callbackLocation);
        // Add the assertion to the policy
        myPolicy.Assertions.Add(myAssertion);
        //Set the custom policy you have created on the client proxy 
        conv.SetPolicy(myPolicy);
    }
 
     /*
     * getStatus invokes Conversation's getRequestStatus method.
     * getRequestStatus is a polling method that is an alternative
     * for web services that cannot recieve callbacks.
     * 
     * Note that a conversation must be started with startRequest before
     * this method may be invoked.  If not, or if this method is invoked
     * outside of a conversation for any reason, it will get back a SOAP
     * fault indicating that the conversation does not exist.
     */
    [WebMethod(EnableSession = true)]
    public String getStatus()
    {
        String result;
 
        /*
         * Create an instance of the proxy for the Conversation
         * web service.  We could probably persist the proxy instance
         * in session state, but chose not to.
         */
        ConversationServiceSoapBinding conv = new ConversationServiceSoapBinding();
 
        /*
         * change the destination to the ReplyTo endpoint reference we cached on session state in
         * the start method.
         */
        conv.RequestSoapContext.Addressing.Destination = (EndpointReference)Session["ConversationReplyTo"];
        /* 
         * Invoke the getRequestStatus method of the web service.
         */
        result = conv.getRequestStatus();
        return result;
    }
 
    /*
     * finish invokes Conversation's terminateRequest method, which
     * terminates the current conversation.
     * 
     * Note that a conversation must be started with startRequest before
     * this method may be invoked.  If not, or if this method is invoked
     * outside of a conversation for any reason, it will get back a SOAP
     * fault indicating that the conversation does not exist.
     */
    [WebMethod(EnableSession = true)]
    public void finish()
    {
        /*
         * Create an instance of the proxy for the Conversation
         * web service.  We could probably persist the proxy instance
         * in session state, but chose not to.
         */
        ConversationServiceSoapBinding conv = new ConversationServiceSoapBinding();
 
        /*
         * change the destination to the ReplyTo endpoint reference we cached on session state in
         * the start method. Both "continue" and "finish" methods use the same destination.
         */
        conv.RequestSoapContext.Addressing.Destination = (EndpointReference)Session["ConversationReplyTo"];
        /* 
         * Invoke the terminateRequest method of the web service.
         */
        conv.terminateRequest();
    }
 
    /*
     * onResultReady is a callback handler for the onResultReady
     * callback that Conversation.jws can optionally use to return
     * its results.
     * 
     * .NET WSE3.0 does not support callbacks directly, but a callback is just
     * a method invocation message.  So if you construct a WebMethod with
     * the same signature as the callback and set the XML namespace
     * properly, it serves as a callback handler.
     * 
     */
    [WebMethod]
    [SoapDocumentMethod(OneWay = true, 
        Action = "http://www.openuri.org/ConversationService_CallbackInterface/onResultReady", 
        RequestElementName = "http://www.openuri.org/", 
        ResponseNamespace = "http://www.openuri.org/"
        )]
    public void onResultReady(String result)
    {
        /*
         * When the callback is invoked, log a message to the
         * hardcoded file c:\temp\ConversationClient.log.
         * 
         * Note: if c:\temp does not exist on this server, an
         * Exception will be raised.  Since it is not handled here,
         * it will be returned as a SOAP fault to the Conversation
         * web service.
         */
        TextWriter output;
        output = File.AppendText("c:\\temp\\ConversationClient.log");
        String msg = "[" + DateTime.Now.ToString() + "] callback received";
        output.WriteLine(msg);
        output.Flush();
        output.Close();
    }
 
    
}
 
public class MyFilter : Microsoft.Web.Services3.SoapFilter
{
    private String callbackLocation;
 
    public MyFilter(String callbackLocation)
    {
        this.callbackLocation = callbackLocation;
    }
    
    public override SoapFilterResult ProcessMessage(SoapEnvelope envelope)
    {
 
       //create the CallbackTo soap element.
       XmlDocument xmldoc = new XmlDocument();
       XmlElement xmlEle = xmldoc.CreateElement("callback", "CallbackTo", "http://www.openuri.org/2006/03/callback");
       
       //create the CallbackTo endpoint reference.
       Address callbacto = new Address(new Uri(callbackLocation));      
       XmlElement xmlEle2 =new EndpointReference(callbacto).GetXml(xmldoc);
       //add the CallbackTo endpoint reference into CallbackTo SOAP element.
       xmlEle.AppendChild(xmlEle2.FirstChild);
       //add the whole CallbackTo SOAP element into SOAP header. 
       XmlNode callbackheader = envelope.ImportNode(xmlEle, true);
       envelope.DocumentElement.FirstChild.AppendChild(callbackheader);
       return SoapFilterResult.Continue;
 
    }
}
 
public class MyPolicyAssertion : Microsoft.Web.Services3.Design.PolicyAssertion
{
    private String callbackLocation;
 
    public MyPolicyAssertion(String callbackLocation)
    {
        this.callbackLocation = callbackLocation;
    }
    
    public override  SoapFilter CreateClientInputFilter(FilterCreationContext context)
    {
        return null;
    }
 
 
    public override  SoapFilter CreateClientOutputFilter(FilterCreationContext context)
    {
        //use MyFilter to add the CallbackTo header in the outbound soap message. 
        return new MyFilter(callbackLocation);
    }
    
    public override  SoapFilter CreateServiceInputFilter(FilterCreationContext context)
    {
        return null;
    }
    
    public override  SoapFilter CreateServiceOutputFilter(FilterCreationContext context)
    {
        return null;
    }
 
}

build.xmlファイル

サンプルのbuild.xmlファイルを例4-3に示します。

build.xmlは、サンプル・ソース・ファイルを新しいWL_HOME\samples\server\examples\src\examples\webservices\convディレクトリにコピーすることを前提としています。WL_HOMEは、WebLogic Serverがインストールされているディレクトリです。

build.xmlを使用するには、まずWL_HOME\samples\domains\wl_server>setExamplesEnv.cmd(shを実行してサンプルの環境を正しく設定し、サンプルのサーバーを開始しておくことも必要です。

このサンプルには、ビルド・ファイルの機能を説明するコメントとターゲットが含まれています。

例4-3 build.xml File

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="webservices.conversation" default="all" basedir=".">
 
  <!-- set global properties for this build -->
  <property file="../../../examples.properties"/>
 
  <property name="client.dir" value="${client.classes.dir}/webservices_conversation" />
  <property name="package.dir" value="examples/webservices/conv"/>
  <property name="package" value="examples.webservices.conv"/>
  <property name="ear.dir" value="${examples.build.dir}/webservicesConversationEar" />
 
  <path id="client.class.path">
    <pathelement path="${java.class.path}"/>
  </path>
 
  <!-- Web service WLS Ant task definitions -->
  <taskdef name="jwsc"
    classname="weblogic.wsee.tools.anttasks.JwscTask" />
  <taskdef name="clientgen"
      classname="weblogic.wsee.tools.anttasks.ClientGenTask" />
 
  <target name="all" depends="build, deploy"/>
 
 
  <target name="clean">
    <delete dir="${ear.dir}"/>
  </target>
 
  <!-- Target that builds the conversational  Web service -->
  <target name="build" description="Target that builds the MTOM Web service">
    <jwsc
      srcdir="${examples.src.dir}/${package.dir}"
      sourcepath="${examples.src.dir}"
      destdir="${ear.dir}"
      classpath="${java.class.path}"
      keepGenerated="true"
      deprecation="${deprecation}"
      debug="${debug}">
        <jws file="ConversationService.java">
                <WLHttpTransport contextPath="/samples/async" serviceURI="conversation.jws"/>
                </jws>
    </jwsc>
  </target>
 
  
 
  <!-- Target that deploys the conversational Web service -->
  <target name="deploy" description="Target that deploys the conversational Web service">
    <wldeploy
      action="deploy"
      source="${ear.dir}"
      user="${wls.username}"
      password="${wls.password}"
      verbose="true"
      adminurl="t3://${wls.hostname}:${wls.port}"
      targets="${wls.server.name}"
      failonerror="${failondeploy}"/>
  </target>
 
  <!-- Target that undeploys the conversational Web service -->
  <target name="undeploy" description="Target that deploys the conversational Web service">
    <wldeploy
      action="undeploy"
      name="webservicesConversationEar"
      user="${wls.username}"
      password="${wls.password}"
      verbose="true"
      adminurl="t3://${wls.hostname}:${wls.port}"
      targets="${wls.server.name}"
      failonerror="${failondeploy}"/>
  </target>
 
</project>

会話型Webサービスを再デプロイする際にクライアント側で考慮すべき事項

WebLogic Serverでは、本番再デプロイメントがサポートされています。つまり、会話型WebLogic Webサービスの更新後の新しいバージョンを、同じWebサービスの古いバージョンと並行してデプロイできます。

WebLogic Serverでは、新しいクライアントのリクエストのみが新しいバージョンに転送されるように、クライアント接続が自動的に管理されます。再デプロイメント時にすでにWebサービスに接続していたクライアントは、作業が完了するまで古いバージョンのサービスを使用し続け、それらの作業が完了した時点で、WebLogic Serverが古いWebサービスを自動的にリタイアします。クライアントが会話型Webサービスに接続されている場合は、既存の会話がクライアントによって明示的に終了されるか、またはタイムアウトになったときに、そのクライアントの作業が完了したと見なされます。

本番再デプロイメントとWebサービス・クライアントの詳細は、『Oracle WebLogic Server JAX-RPC Webサービス・スタート・ガイド』のWebサービスを再デプロイする際にクライアントで考慮すべき事項に関する項を参照してください。