Webサービス・プログラミングのヒントと秘訣: JAX-RPCでSOAP添付

JAX-RPCは添付データ付きのSOAPをサポートします。この記事では、どうしたらJAX-RPC APIを使用してMIME添付データを送信できるかを説明します。

Russell Butek, Developer, IBM

Russell Butekは、IBM WebSphereのWebサービス・エンジンの開発者の一人です。JSR (JAX-RPC Java Specification Request) エキスパート・グループのIBM代表でもあります。Apache AXISのSOAPエンジンの実装にも関与し、AXIS 1.0でJAX-RPC 1.0対応を行いました。以前はIBMのCORBA ORBの開発者であり、そして、・・・ポータブル・インターセプター作業部会(ここで議長を務める)、コア作業部会、インターオペラビリティ作業部会・・・など、数々のOMG (Object Management Group) 作業部会でIBM代表を務めました。



2004年 2月 27日

SOAPメッセージ・プロトコルを使用すれば、SOAPメッセージをとおしてMIME添付を送信できます。WSDLは添付に関する記述を提供します。JAX-RPCは添付に関するWSDL記述のマッピングをJava成果物へ提供します。この記事では、SOAPメッセージ内の添付データを送信するために、どのようにしてJAX-RPCマッピングを活用するかを説明します。

WSDL

残念ながら、添付に関するWSDL記述はそれほどに簡単ではありません。リスト1に示されるWSDL(特に太字で表記されたbinding内のエレメント)に注目してください。

リスト1. 添付と関連するWSDL
<?xml version="1.0" encoding="utf-8"?>
<definitions
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    targetNamespace="urn:attachment.tip"
    xmlns:tns="urn:attachment.tip">
  <message name="empty"/>
  <message name="imageMsg">
    <part name="image" type="xsd:hexBinary"/>
  </message>
  <message name="octetMsg">
    <part name="octet" type="xsd:hexBinary"/>
  </message>
  <portType name="AttachmentTip">
    <operation name="sendImage">
      <input message="tns:imageMsg"/>
      <output message="tns:empty"/>
    </operation>
    <operation name="sendOctet">
      <input message="tns:octetMsg"/>
      <output message="tns:empty"/>
    </operation>
  </portType>
  <binding name="AttachmentBinding" type="tns:AttachmentTip">
    <soap:binding style="rpc"
                  transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="sendImage">
      <soap:operation soapAction=""/>
      <input>
        <mime:multipartRelated>
          <mime:part>
            <soap:body use="literal"/>
          </mime:part>
          <mime:part>
            <mime:content part="image" type="image/jpeg"/>
          </mime:part>
        </mime:multipartRelated>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="sendOctet">
      <soap:operation soapAction=""/>
      <input>
        <mime:multipartRelated>
          <mime:part>
            <soap:body use="literal"/>
          </mime:part>
          <mime:part>
            <mime:content part="octet" type="application/octet-stream"/>
          </mime:part>
        </mime:multipartRelated>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="AttachmentService">
    <port name="AttachmentTip" binding="tns:AttachmentBinding">
      <soap:address
          location="http://localhost:9080/attachment/services/AttachmentTip"/>
    </port>
  </service>
</definitions>

WS-I と添付データ

左側に位置するパラグラフにて記述されるとおり、MIMEタイプはWSDLの「インターフェース」で記述されません。WS-I organization (参考文献を参照)は、全MIMEタイプに新規のXMLタイプ(wsi:swaRef)を導入して、少なくとも部分的にはこの欠陥の修正を試みています。しかしながら、この記事作成時にはまだこのタイプは準備中であり、標準化されたJava言語のバインディング(binding)はまだこれに対応していません。

まず、始めの部分からbindingの部分にたどり着くまで、MIME関連の情報が無いことに注目してください。ひとまずbindingのことを忘れ、WSDLの「インターフェース」(portType と message)に注目すれば、2つのoperation(sendImagesendOctet)がそこにあるのがわかります。それぞれが(byte []にマッピングする)hexBinary入力を持ちます。この情報からだけでも、portTypeがJava言語のService Endpoint Interface (SEI)にマッピングすることが比較的容易に予測できます。そのSEIには2つのメソッド(それぞれに1つのbyte[]パラメーター)があります。これは妥当な予測であり、(添付データが)MIMEタイプでなければそれは正しいです。しかし、(添付データが)MIMEタイプの場合、実際のパラメーター・タイプを認識するためにbindingを調べる必要があります。

bindingの中を見れば、これらのoperationの入力のコンテント・タイプは実を言えばhexBinary では無く、MIME(image/jpeg そしてapplication/octet-stream)であるのがわかります。JAX-RPCは、それぞれがjava.awt.Imagejavax.activation.DataHandler にマッピングするように定義します。


サービス・エンドポイント・インターフェース

リスト1のWSDLから生成されたJava言語SEIを、リスト2に表記します。

リスト2. AttachmentTip SEI
package tip.attachment;
import java.awt.Image;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.activation.DataHandler;
public interface AttachmentTip extends Remote {
    public void sendImage(Image image) throws RemoteException;
    public void sendOctet(DataHandler octet) throws RemoteException;
}

WSDL内(bindingによればimage/jpegのMIMEコンテントを含む)のsendImageのoperationは、java.awt.Imageパラメーターの付属するJavaプログラム・メソッドになります。これはきれいに整理されています。MIMEタイプからのJavaタイプへの整然としたマッピングを、表1に表記します。

表1 - JAX-RPC による、MIMEタイプからJavaタイプへのマッピング
MIMEタイプJavaタイプ
image/gif, image/jpegjava.awt.Image
text/plainjava.lang.String
multipart/*javax.mail.internet.MimeMultipart
text/xml, application/xmljavax.xml.transform.Source

SendOctetのoperationでそうしたように、この表内に無いMIMEタイプを定義すれば、JAX-RPC実装はjavax.activation.DataHandler にタイプをマッピングします。DataHandler タイプは Java Activation Framework(JAF - 下記の詳細、そして参考文献の章にあるJAFページへのリンクを参照して下さい。)にて定義されています。


クライアント実装

ここからは、使い慣れたJAX-RPC実装を使用してAttachmentTip WSDLからクライアント側マッピングを生成したと想定します。クライアント実装はこれらのマッピング(特にリスト2で示されるAttachmentTip SEI)に依存します。

添付データのクライアント実装は、先ずService からSEIの実装を入手します。リスト3getTip メソッドを見れば、それがどのように実行されるかがわかります。(ServiceFactoryそしてService についての考察は、この記事では取り上げませんので、参考文献でより詳しい情報を入手して下さい。)

sendImage メソッドを呼び出す

SEI実装を一度入手すれば、添付データ(この例では、任意の名前の付いたファイルの中にあります)付きのメソッドを呼び出せます。sendImage の場合、添付データがjava.awt.Imageであるだけのことです。JAX-RPC実装は、全てのイメージが添付データとして送信されることを知り、SOAPメッセージをそれに応じて構築します。添付が関与していることを、クライアント側のプログラマーは知る必要はありません。SendImageへの呼び出しは、リスト3のコードにて太字で表記されています。

リスト3. AttachmentTip クライアント実装の sendImage 呼び出し
package tip.attachment;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
public class AttachmentTipClient {
    static AttachmentTip getTip() throws Exception {
        QName serviceName = new QName(
                "urn:attachment.tip",
                "AttachmentService");
        URL wsdlLocation = new URL(
                "http://localhost:9080/attachment/services/AttachmentTip?wsdl");
        ServiceFactory factory = ServiceFactory.newInstance();
        Service service = factory.createService(wsdlLocation, serviceName);
        QName portName = new QName("", "AttachmentTip");
        return (AttachmentTip) service.getPort(
                portName,
                AttachmentTip.class);
    }
static void sendImage(AttachmentTip tip, String fileName)
            throws RemoteException {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Image image = toolkit.createImage(fileName);
        tip.sendImage(image);
    }
    public static void main(String[] args) {
        try {
            AttachmentTip tip = getTip();
sendImage(tip, args[0]);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

sendOctet メソッドの呼び出し

指定されていないMIMEタイプのマッピングに関する警告

JAX-RPCは、(表1に表記されていない)MIMEタイプをサポートする実装を必要としません。実装は指定されていないMIMEタイプをDataHandler にマッピングしないかも知れません。例として、WebSphere Webサービスは、Application Serverのバージョン6.0まではこのマッピングをサポートしません。

JAX-RPCにマッピングを定義された数少ないMIMEタイプを使えば、何もかもが簡単です(表1参照)。明確なJAX-RPCマッピングと縁の無いMIMEタイプには、javax.activation.DataHandler オブジェクトを使う手が残されています。このクラスはJava Activation Framework (JAF -参考文献を参照してください)の一部ですのでJAFについて多少なりとも知るべきですが、それほどに難しくはありません。DataHandler は(その代わりとして入力ストリームと出力ストリームを含む)javax.activation.DataSource を含みます。大半のJavaプログラミング・タイプとストリームの間で変換(どちらの方向も可能)が比較的容易にできます。そのうえに、activation framework そのものが少しばかり役立ちます。仮に添付データがこのようにファイル内にあれば、activation framework がjavax.activation.FileDataSource クラスを供給しますので、ストリームの段階をバイパスできます。sendOctet を呼び出しDataHandler にそれを手渡す新規のメソッドをリスト3のコードに追加すれば、リスト4のコードができあがります。

リスト4. 完全な AttachmentTip クライアント実装
package tip.attachment;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
import java.rmi.RemoteException;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
public class AttachmentTipClient {
    static AttachmentTip getTip() throws Exception {
        QName serviceName = new QName(
                "urn:attachment.tip",
                "AttachmentService");
        URL wsdlLocation = new URL(
                "http://localhost:9080/attachment/services/AttachmentTip?wsdl");
        ServiceFactory factory = ServiceFactory.newInstance();
        Service service = factory.createService(wsdlLocation, serviceName);
        QName portName = new QName("", "AttachmentTip");
        return (AttachmentTip) service.getPort(
                portName,
                AttachmentTip.class);
    }
    static void sendImage(AttachmentTip tip, String fileName)
            throws RemoteException {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Image image = toolkit.createImage(fileName);
        tip.sendImage(image);
    }
static void sendOctet(AttachmentTip tip, String fileName)
            throws RemoteException {
        FileDataSource fds = new FileDataSource(fileName);
        DataHandler dh = new DataHandler(fds);
        tip.sendOctet(dh);
    }
    public static void main(String[] args) {
        try {
            AttachmentTip tip = getTip();
            sendImage(tip, args[0]);
sendOctet(tip, args[0]);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

両方の添付用オペレーションに同一のファイルをデータとして使用したことに注目してください。しかし、sendOctet に関して言えば、ファイルのコンテントはapplication/octet-stream です。それが実はイメージなのかどうかなど、それは気にも留めません。application/octet-stream は、FileDataSource のデフォルト・コンテント・タイプなので、ここで使用するうえで大いに役立ちました。仮にデータをファイルとして持つほどに運がよいわけではなく、application/octet-stream 以外の形でそれを送信しなくてはならなければ、独自のDataSource実装を作成する必要があります。それは単純なインターフェースなので、それほどに難しくはないでしょう(それでも、この課題に自主的に取り組まれることをおすすめします)。


まとめ

ここで説明したとおり、JAX-RPCマッピングを介して添付データを送信するのはかなり簡単なことです。アプリケーション・プログラマーは添付データの存在を全く知る必要がありません。最悪でも、プログラマーはDataHandlerDataSource、そしてストリームに気をつかえばよいだけです。


ダウンロード

内容ファイル名サイズ
ws-tip-soapjax.zip40.0 KB

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services, XML
ArticleID=245146
ArticleTitle=Webサービス・プログラミングのヒントと秘訣: JAX-RPCでSOAP添付
publish-date=02272004