intra-mart Accel Platform Webサービス Java開発プログラミングガイド 第3版 2017-04-01

付録

トラブルシューティング

https で提供されている WSDL を利用する場合

以下のような、WSDL が https で提供されている場合のスタブによるWebサービスの実行を行うためには、接続先のサーバ証明書の取得・登録が必要です。
  • https://<HOST>/<CONTEXT_PATH>/services/SampleWebService?wsdl
以下の手順に従って、サーバ証明書の取得・登録を行います。
  1. 接続先のサーバ証明書を取得します。
    サーバ証明書の取得方法はいくつかありますが、ここでは Windows 環境の Internet Explorer 9 を利用して証明書を取得する方法を示します。
    1. Internet Explorer 9 を開き、WSDL の URL を入力してアクセスします。
    2. Alt キーを押下してメニューバーを開き、「ツール」-「インターネット オプション」を選択します。
    3. 「コンテンツ」タブを開き、「証明書」をクリックします。
    4. 取得したい証明書を選択して「エクスポート」をクリックします。
    5. ウィザードを進めてサーバ証明書ファイルを保存します。
  2. JDK に含まれる keytool を利用して、サーバ証明書をキーストアに追加します。
    例: サーバ証明書ファイルが C:\temp\server.crt に保存されており、別名「sample_alias」でキーストアエントリに追加する場合
    keytool -import -alias sample_alias -file C:\temp\server.crt
    

    コラム

    上記コマンドを実行すると、ユーザのホームディレクトリの「.keystore」ファイルに、キーストアが作成されます。
    keytool の詳細は、以下「JDK ドキュメントの keytool - 鍵と証明書の管理ツール」を参照してください。

  3. アプリケーションサーバの JVM のシステムプロパティに「javax.net.ssl.trustStore」を追加します。
    例: Resin のインストール先が C:\resin で、ユーザ名が user_name の場合

    C:\resin\conf\resin.properties

    jvm_args : -Djavax.net.ssl.trustStore="C:\Users\user_name\.keystore"
    

    コラム

    すでに jvm_args が存在する場合は、末尾に半角空白で1文字空けて追記してください。
また、WSDL の URL が https で始まっていたとしても、WSDL に記述されているエンドポイントが https でない場合は、スタブ を利用する際に、明示的にエンドポイントを指定してください。
// スタブのコンストラクタの第1引数にエンドポイントを指定します。
new SampleWebServiceStub("https://localhost/imart/services/SampleWebService");

「指定した要求に失敗しました」が発生する場合

本現象が発生した場合に考えられる原因は、以下の通りです。
  • 指定した Web サービスを実行する権限がない可能性があります。
解決方法の詳細は「Webサービス 認証・認可 仕様書」-「認証・認可のSOAPフォルト・コード」の「wsse:RequestFailed」を参照してください。

「指定した RequestSecurityToken を理解できません」が発生する場合

本現象が発生した場合に考えられる原因は、以下の通りです。
  • 認証タイプに対応する認証モジュールが存在しない可能性があります。
解決方法の詳細は「Webサービス 認証・認可 仕様書」-「認証・認可のSOAPフォルト・コード」の「wsse:BadRequest」を参照してください。

「要求が無効か、形式が間違っています」が発生する場合

本現象が発生した場合に考えられる原因は、以下の通りです。
  • SOAP ボディにユーザ情報が存在していない可能性があります。
  • ユーザ情報が格納されている要素名が「wsUserInfo」とされていない可能性があります。
  • Web サービスとして公開する Java クラスのコンパイル方法が誤っている可能性があります。
WSDL の URL をブラウザで開き、Web サービスの関数定義内の引数名を確認してください。

■正

<xs:element name="add">
   <xs:complexType>
      <xs:sequence>
         <xs:element name="wsUserInfo" type="ax22:WSUserInfo" nillable="true" minOccurs="0"/>
         <xs:element name="member" type="ax24:Member" nillable="true" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
</xs:element>

■誤

<xs:element name="add">
   <xs:complexType>
      <xs:sequence>
         <xs:element name="param0" type="ax22:WSUserInfo" nillable="true" minOccurs="0"/>
         <xs:element name="param1" type="ax24:Member" nillable="true" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
</xs:element>
上記のように、引数名が「param0」「param1」のようになっている場合は、Java クラスのコンパイル方法が誤っています。
解決方法の詳細は「Webサービス 認証・認可 仕様書」-「認証・認可のSOAPフォルト・コード」の「wsse:InvalidRequest」を参照してください。

サンプルコード

Webサービス のタイムアウト時間を指定する

Webサービス 実行時のタイムアウト時間を指定するにはスタブに対してタイムアウト時間を設定します。
final SampleWebServiceStub client = new SampleWebServiceStub(ENDPOINT);
// タイムアウトを5秒(5000ミリ秒)に指定
client._getServiceClient().getOptions().setTimeOutInMilliSeconds(5000);

バイナリファイルを送受信するサンプル

Web サービスとして公開する Webサービス・プロバイダ の実装クラスのメソッドの引数、および、返却値の型に「byte[]」を指定することで、バイナリファイルを送受信できます。
引き渡されたバイト配列は自動的に Base64 にエンコードされ SOAP メッセージとして送受信されます。
以下では、バイナリファイルを送受信するサンプルを動作させるまでの手順を説明します。

Webサービス・プロバイダ を作成する

Webサービス・プロバイダ の作成」と同様に Webサービス・プロバイダ を実装します。
このサンプルでは、「開発環境を用意する」と「依存関係を解決する」は割愛します。
sample.web_service.provider.PublicStorageAccessService.java を用意します。
このクラスに定義されているメソッド「loadFile()」、および、「saveFile()」を Web サービスとして公開します。
PublicStorageAccessService.java の内容は以下の通りです。クラスの作成方法については「Web サービス処理を実装する」を参照してください。
package sample.web_service.provider;

import java.io.IOException;

import jp.co.intra_mart.foundation.service.client.file.PublicStorage;
import jp.co.intra_mart.foundation.web_service.auth.WSUserInfo;

import org.apache.axis2.AxisFault;

public class PublicStorageAccessService {

    public byte[] loadFile(final WSUserInfo wsUserInfo, final String path) throws AxisFault {
        final PublicStorage storege = new PublicStorage(path);
        try {
            return storege.load();
        } catch (final IOException e) {
            throw AxisFault.makeFault(e);
        }
    }

    public Boolean saveFile(final WSUserInfo wsUserInfo, final String path, final byte[] data) throws AxisFault {
        final PublicStorage storege = new PublicStorage(path);
        try {
            storege.save(data);
            return Boolean.TRUE;
        } catch (final IOException e) {
            throw AxisFault.makeFault(e);
        }
    }

}
PublicStorageAccessServiceを Webサービス として公開するための services.xml を作成します。
services.xmlは src/main/webapp/WEB-INF/services/sample_public_storage/META-INF/services.xml に配置します。
services.xml の内容は以下の通りです。
<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>
    <service name="SamplePublicStorageAccessService">
        <parameter name="ServiceClass">sample.web_service.provider.PublicStorageAccessService</parameter>
        <module ref="im_ws_auth"/>
        <messageReceivers>
            <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
            <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"  class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
        </messageReceivers>

        <parameter name="authz-uri">service://intra-mart.jp/public-resources/welcome-to-intramart</parameter>

        <operation name="loadFile">
            <parameter name="authz-uri">service://intra-mart.jp/public-resources/welcome-to-intramart</parameter>
        </operation>

        <operation name="saveFile">
            <parameter name="authz-uri">service://intra-mart.jp/public-resources/welcome-to-intramart</parameter>
        </operation>

    </service>
</serviceGroup>
Webサービス をデプロイする」と同様にデプロイを行います。

Webサービス・クライアント を作成する

Webサービス・クライアント の作成」と同様に Webサービス・クライアント を実装します。
このサンプルでは、「開発環境を用意する」は割愛します。
SamplePublicStorageAccessService にアクセスするためのスタブを作成します。
スタブクラスを作成する」の通りに、スタブクラスを作成します。
WSDL のURLは http://<HOST>:<PORT>/<CONTEXT_PATH>/services/SamplePublicStorageAccessService?wsdl です。
<HOST><PORT>、および、<CONTEXT_PATH> については、Webサービス・プロバイダ が起動しているアプリケーションサーバを指すものに変更してください。
Webサービス・クライアント を実装する」の手順と同様に、上記で作成したスタブクラス情報をクラスパスに追加します。
Webサービス 実行クラス sample.web_service.client.PublicStorageAccessRunner.java を作成します。
PublicStorageAccessRunner.java の内容は以下の通りです。
package sample.web_service.client;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.rmi.RemoteException;

import javax.activation.DataHandler;

import jp.co.intra_mart.foundation.web_service.util.impl.WSAuthDigestGenerator4WSSE;

import org.apache.axis2.AxisFault;

import sample.web_service.provider.SamplePublicStorageAccessServiceStub;
import sample.web_service.provider.SamplePublicStorageAccessServiceStub.LoadFile;
import sample.web_service.provider.SamplePublicStorageAccessServiceStub.LoadFileResponse;
import sample.web_service.provider.SamplePublicStorageAccessServiceStub.SaveFile;
import sample.web_service.provider.SamplePublicStorageAccessServiceStub.WSUserInfo;

/**
 * スタブを利用してSamplePublicStorageAccessServiceのオペレーションを実行するクライアントクラスのサンプルです。
 */
public class PublicStorageAccessRunner {

    // ホスト名、ポート番号、コンテキストパスは適宜置き換えてください。
    private static final String ENDPOINT = "http://localhost:8080/imart/services/SamplePublicStorageAccessService";

    private static final String USER_CD = "aoyagi";

    private static final String PASSWORD = "aoyagi";

    private static final String LOGIN_GROUP_ID = "default";

    public static void main(final String[] args) {
        try {
            new PublicStorageAccessRunner().loadFile();
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * SamplePublicStorageAccessService#loadFile を実行するサンプルです。<br>
     * パブリックストレージの"sample/test.data"をカレントディレクトリの"temp.data"にコピーします。
     */
    public void loadFile() throws IOException {
        // Webサービス・オペレーションへのパラメータを作成します。
        final LoadFile parameter = new LoadFile();
        parameter.setWsUserInfo(generateWSUserInfo());
        parameter.setPath("sample/test.data");

        // Webサービスを実行します。
        final SamplePublicStorageAccessServiceStub client = getStub();
        final LoadFileResponse response = client.loadFile(parameter);
        final DataHandler handler = response.get_return();

        // カレントディレクトリのファイル"temp.data"に内容を保存します。
        final File file = new File("temp.data");
        final FileOutputStream fos = new FileOutputStream(file);
        final InputStream in = handler.getInputStream();

        final byte[] buff = new byte[1024];
        try {
            while (true) {
                final int len = in.read(buff);
                if (len != -1) {
                    fos.write(buff, 0, len);
                } else {
                    break;
                }
            }
            fos.flush();
        } finally {
            fos.close();
            in.close();
        }

        // 実行結果を標準出力します。
        System.out.println("Out file : " + file.getAbsolutePath());
    }

    /**
     * SamplePublicStorageAccessService#saveFile を実行するサンプルです。<br>
     * カレントディレクトリの"temp.data"をパブリックストレージの"sample/test.data"にコピーします。
     */
    public void saveFile() throws RemoteException, MalformedURLException {
        // Webサービス・オペレーションへのパラメータを作成します。
        final SaveFile parameter = new SaveFile();
        parameter.setWsUserInfo(generateWSUserInfo());
        parameter.setPath("sample/test.data");
        final File file = new File("temp.data");
        parameter.setData(new DataHandler(file.toURI().toURL()));

        // Webサービスを実行します。
        final SamplePublicStorageAccessServiceStub client = getStub();
        client.saveFile(parameter);

        // 実行結果を標準出力します。
        System.out.println("Success.");
    }

    private WSUserInfo generateWSUserInfo() {
        final WSUserInfo info = new WSUserInfo();
        info.setLoginGroupID(LOGIN_GROUP_ID);
        info.setUserID(USER_CD);
        info.setPassword(WSAuthDigestGenerator4WSSE.createWsseAuthString(USER_CD, PASSWORD));
        info.setAuthType(WSAuthDigestGenerator4WSSE.authType);

        return info;
    }

    private SamplePublicStorageAccessServiceStub getStub() throws AxisFault {
        final SamplePublicStorageAccessServiceStub client = new SamplePublicStorageAccessServiceStub(ENDPOINT);

        return client;
    }

}

Webサービス を実行する

このサンプルプログラムは、Webサービス・クライアント のローカルファイルと Webサービス・プロバイダ 側の PublicStorage 内にあるファイルの内容を送受信します。
  • バイナリファイルを受信する(SamplePublicStorageAccessService#loadFile)

    Web サービスを経由して Webサービス・プロバイダ 側の PublicStorage からファイルの中身を取得し、Webサービス・クライアント のローカルファイルに保存します。
    e Builder上で PublicStorageAccessRunner.java を右クリックし、「実行」-「Java アプリケーション」を選択します。
    loadFile を実行した場合の処理の流れは、以下の通りです。
../../_images/appendix_3.png
  • バイナリファイルを送信する(SamplePublicStorageAccessService#saveFile)

    Webサービス・クライアント のローカルファイルを読み取り、Web サービスを経由して Webサービス・プロバイダ 側の PublicStorage にファイルを保存します。
    PublicStorageAccessRunner.javaの main メソッドで実行するメソッドを loadFile から saveFile に変更します。
    e Builder上で PublicStorageAccessRunner.java を右クリックし、「実行」-「Java アプリケーション」を選択します。
    saveFile を実行した場合の処理の流れは、以下の通りです。
../../_images/appendix_2.png

注意

Web サービスとして公開する関数の引数に JavaBean が指定されている場合、その JavaBean 内のバイト配列(byte[])型のプロパティは、正常にデータが送受信されません。
これは Apache Axis2 の現行仕様による制限です。
バイナリファイルを送受信する場合は、JavaBean のプロパティではなく、Web サービスとして公開する関数の引数としてバイト配列(byte[])を指定してください。