目次


ヒント

JAXMによるSOAPメッセージの送受信

手動でメッセージを生成して送信するのに必要なステップの多くをJava APIで自動化する

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: ヒント

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:ヒント

このシリーズの続きに乞うご期待。

Web サービスの基礎は、標準化された形式でメッセージを送受信することにより、すべてのシステムがそれらのメッセージを理解できるようにするところにあります。典型的なメッセージ形式は、Simple Object Access Protocol (SOAP) です。SOAPメッセージは、手動で生成して送信することもできます。しかし、(Java API for XML Messaging (JAXM) から派生した) SOAP with Attachments API for Java (SAAJ) を使用すると、接続の作成や、実際のメッセージの作成と送信など、必要なステップの多くを自動化することが可能です。このヒントは、同期 SOAP メッセージの作成と送信の作業を記録したものです。

このプロセスには、次の5つのステップが関係しています。

  1. SOAP 接続の作成
  2. SOAP メッセージの作成
  3. メッセージへの情報の取り込み
  4. メッセージの送信
  5. 応答の取得

SAAJ は、Java Web Services Developer Pack 1.2 (「参考文献」を参照) に含まれています。このパッケージには Tomcat Web サーバーのコピーとサンプル・アプリケーションが含まれており、皆さん独自のサービスをホストすることが可能です。

インストールと設定

Java Web Services Developer Pack 1.2 のセットアップは、パッケージに組み込まれている Tomcat Web サーバーからメッセージを送信するようにする場合は、簡単です。この記事で行うように、スタンドアロン・アプリケーションからメッセージを送信するには、以下のステップに従います。

  1. JWSDP 1.2 を http://java.sun.com/webservices/downloads/webservicespack.html からダウンロードします。
  2. JWSDP 1.2 を指示にしたがってインストールします。
  3. Java 1.4 を使用している場合、JWSDP 1.2 に組み込まれている XML 関連のクラスを上書きする必要があります。以下のディレクトリーを作成してください。
    <JAVA_HOME>/jre/lib/endorsed
    そして、このディレクトリーへ以下のディレクトリーからファイルをコピーします。
    <JWSDP_HOME>/jaxp/lib/endorsed
    (ここで JAVA_HOME と JWSDP_HOME は、それぞれ Java のインストール・ディレクトリーと JWSDP のインストール・ディレクトリーを表します。)
  4. 以下のファイルをクラスパスに追加します。
    • <JWSDP_HOME>/saaj/lib/saaj-api.jar
    • <JWSDP_HOME>/saaj/lib/saaj-impl.jar
    • <JWSDP_HOME>/jwsdp-shared/lib/commons-logging.jar
    • <JWSDP_HOME>/jwsdp-shared/lib/mail.jar
    • <JWSDP_HOME>/jwsdp-shared/lib/activation.jar
    • <JWSDP_HOME>/jaxp/lib/endorsed/dom.jar
    • <JWSDP_HOME>/jaxp/lib/endorsed/xercesImpl.jar
    • <JWSDP_HOME>/jaxp/lib/endorsed/sax.jar
    • <JWSDP_HOME>/jaxp/lib/endorsed/xalan.jar

これで、システム上のどこからでもスタンドアロンのプログラムを使ってメッセージを送信することができるはずです。

SOAPメッセージの構造

まずは、メッセージそのものの構造を示すところから始めます。基本的な SOAP メッセージは、ヘッダーと本体という 2 つの主要な部分からなるエンベロープで構成されます。これらの部分をどのように使用するかを決めるのはアプリケーションですが、メッセージ全体の構造は、ある特定の XML 構造に従っていなければなりません。たとえば、次の通りです。

リスト 1. サンプルSOAPメッセージ
<SOAP-ENV:Envelope 
        xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
        xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
        xmlns:xsd="http://www.w3.org/1999/XMLSchema"> 
    <SOAP-ENV:Header />
    <SOAP-ENV:Body> 
        <ns1:getPrice xmlns:ns1="urn:xmethods-BNPriceCheck" 
             SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
                  <isbn xsi:type="xsd:string">0672324229</isbn> 
        </ns1:getPrice> 
    </SOAP-ENV:Body> 
</SOAP-ENV:Envelope>

このメッセージでは、ヘッダーは空で、本体にペイロードもしくは配信するメッセージが含まれています。メッセージの内容は、本の価格を要求するものです。

メッセージの構造に注目してください。Envelope 要素に Header および Body 要素が含まれており、これら 3 つの要素は http://schemas.xmlsoap.org/soap/envelope/ 名前空間に属しています。このアプリケーションは SOAPConnection を使用してメッセージを送信します。

接続とメッセージの作成

最初のステップは、全体を取りまとめるクラスと接続を作成することです。

リスト 2. 接続の作成
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;

public class SOAPTip {
    
   public static void main(String args[]) {
        
      try {
      
         //First create the connection
         SOAPConnectionFactory soapConnFactory = 
                            SOAPConnectionFactory.newInstance();
         SOAPConnection connection = 
                             soapConnFactory.createConnection();
         


         //Close the connection            
         connection.close();
            
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

このアプリケーションでは、(SAAJ パッケージに含まれている) SOAPConnection を使って直接送信することもできますし、JAXM パッケージに含まれるメッセージング・プロバイダーを使って間接的に送信することもできます。この例では、アプリケーションは、ファクトリーを使って SOAPConnection を作成します。

さらに、ファクトリーは、メッセージそのものも作成します。

リスト 3. メッセージ・オブジェクトの作成
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;

public class SOAPTip {
    
   public static void main(String args[]) {
        
      try {
     
         //First create the connection
         SOAPConnectionFactory soapConnFactory = 
                            SOAPConnectionFactory.newInstance();
         SOAPConnection connection = 
                             soapConnFactory.createConnection();
         
         //Next, create the actual message
         MessageFactory messageFactory = MessageFactory.newInstance();
         SOAPMessage message = messageFactory.createMessage();
         
         //Create objects for the message parts            
         SOAPPart soapPart =     message.getSOAPPart();
         SOAPEnvelope envelope = soapPart.getEnvelope();
         SOAPBody body =         envelope.getBody();


         //Close the connection            
         connection.close();
            
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

まず、MessageFactory を使ってメッセージそのものを作成します。このメッセージには、中身が空の基本的な構成要素 (envelopeheader など) が既に含まれています。SOAPPart にはenvelope が含まれ、envelope には本体が含まれています。SOAPBody など、必要なオブジェクトへの参照を作成します。

次に、SOAPBody に情報を取り込みます。

リスト 4. 本体への情報の取り込み
...
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;

public class SOAPTip {
    
   public static void main(String args[]) {
        
      try {
...
         //Create objects for the message parts            
         SOAPPart soapPart =     message.getSOAPPart();
         SOAPEnvelope envelope = soapPart.getEnvelope();
         SOAPBody body =         envelope.getBody();

        //Populate the body
        //Create the main element and namespace
        SOAPElement bodyElement = 
                  body.addChildElement(envelope.createName("getPrice" , 
                                                                "ns1", 
                                          "urn:xmethods-BNPriceCheck"));
        //Add content
        bodyElement.addChildElement("isbn").addTextNode("0672324229");

        //Save the message
        message.saveChanges();


        //Check the input
        System.out.println("\nREQUEST:\n");
        message.writeTo(System.out);
        System.out.println();


         //Close the connection            
         connection.close();
            
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

SOAP メッセージの本体には、通常の XML 要素と同様に getPrice などの子要素を追加することができます。したがって、通常の DOM 要素の場合のように、isbn 要素とそのテキスト・ノードを追加することができます。

SAAJ の場合、外部ファイルを使用してメッセージの SOAPPart を直接作成することも可能です。例えば、prepped.msg ファイルには最初のリストに示した XML 構造が含まれており、文書を手動で作成する代わりにこのファイルを呼び出すことができます。

リスト 5. 外部ファイルからメッセージを作成する
...
import javax.xml.soap.SOAPElement;

import java.io.FileInputStream;
import javax.xml.transform.stream.StreamSource;

public class SOAPTip {
    
   public static void main(String args[]) {
...
         //Create objects for the message parts            
         SOAPPart soapPart =     message.getSOAPPart();
         SOAPEnvelope envelope = soapPart.getEnvelope();
         SOAPBody body =         envelope.getBody();

         //Populate the Message
        StreamSource preppedMsgSrc = new StreamSource( 
                 new FileInputStream("prepped.msg"));
        soapPart.setContent(preppedMsgSrc);

         //Save the message
         message.saveChanges();
...
    }
}

StreamSource クラスは通常 XSL 変換の際に使われますが、ここでは FileInputStream を取得するためだけに使用しています。こうして、送信可能な SOAP メッセージの用意ができました。

メッセージの送信

同期メッセージの場合、SOAP メッセージの送信とそれに対する応答の受信は、1つのステップで実行されます。

リスト 6. メッセージの送信
...
public class SOAPTip {
    
   public static void main(String args[]) {
        
...
         //Check the input
         System.out.println("\nREQUEST:\n");
         message.writeTo(System.out);
         System.out.println();

        //Send the message and get a reply   
            
        //Set the destination
        String destination = 
            "http://services.xmethods.net:80/soap/servlet/rpcrouter";
        //Send the message
        SOAPMessage reply = connection.call(message, destination);

         //Close the connection            
         connection.close();         
...
    }
}

実際のメッセージは、call() メソッドを使って送信されます。このメソッドは、引数としてメッセージそのものと宛先を取り、SOAPMessage の型を持つ応答を返します。JAXM の以前のバージョンでは、宛先は Endpoint オブジェクトもしくは URLEndpoint でなければなりませんでしたが、現在のバージョンではオブジェクトでありさえすれば問題ありません。この例では、XMethods にホストされている「本の価格確認」用の Web サービスを使用します。この Web サービスは、本の ISBN を含む要求が送られてくると、その本の価格を返します。

call() メソッドは、返されるSOAPMessage を受け取るまでブロックされています。

応答

返される SOAPMessage (reply) は、送信したメッセージと同じ形式の SOAP メッセージです。そのため、通常の XML メッセージと同じように操作することができます。SOAP では、XSLT を使って応答を直接変換することができます。

リスト 7. 応答を読み出す
...
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.Source;

import javax.xml.transform.stream.StreamResult;

public class SOAPTip {
    
   public static void main(String args[]) {
        
      try {
      
...
         //Send the message
         SOAPMessage reply = connection.call(message, destination);

        //Check the output
        System.out.println("\nRESPONSE:\n");
        //Create the transformer
        TransformerFactory transformerFactory = 
                           TransformerFactory.newInstance();
        Transformer transformer = 
                        transformerFactory.newTransformer();
        //Extract the content of the reply
        Source sourceContent = reply.getSOAPPart().getContent();
        //Set the output for the transformation
        StreamResult result = new StreamResult(System.out);
        transformer.transform(sourceContent, result);
        System.out.println();

         //Close the connection            
         connection.close();
...            
     }
}

Transformer オブジェクトは、通常の XSLT アプリケーションの場合と同じようにして作成します。この例では、内容を出力したいだけなので、スタイル・シートは使いません。ここで出力する内容は、(添付ファイルを含むことのできる SOAP メッセージそのものではなく) メッセージの SOAP 部分全体です。必要なら、処理の前にエンベロープと本体を抽出することもできます。この例では、結果の出力先は単純に System.out にしていますが、変換で通常利用できる任意のものを選択することができます。そして、通常どおりに変換します。

図1. SOAP 要求および応答
図1. SOAP 要求および応答
図1. SOAP 要求および応答

次なるステップは

この単純なアプリケーションは、受信したメッセージを出力するだけのものですが、XML 文書から非常に容易に情報を抽出することが可能です。また、このヒントではメッセージの送受信を同期させた例を示しましたが、任意にダウンロード可能な JAXM API では、SOAPConnection の代わりに ProviderConnection オブジェクトを使用することにより、非同期配信用のメッセージ・プロバイダーを使用することができます。このメッセージ・プロバイダーは、メッセージが正常に送達されるまで、そのメッセージを保持しています。

JAXM では、特殊な SOAP メッセージ (SOAP-RP または ebXML メッセージなど) を簡単に作成できるようにするプロファイル を使用することができます。


ダウンロード可能なリソース


関連トピック

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, SOA and web services
ArticleID=239863
ArticleTitle=ヒント: JAXMによるSOAPメッセージの送受信
publish-date=01222008