intra-mart Accel Platform IM-Propagation プログラミングガイド 初版 2014-05-01

5. データを受け取る側の実装

用意する資材

受信側で用意する資材は、以下の通りです。
../../_images/receiver_1.png
図 受信側の処理
表 用意する資材一覧
番号 資材名 準備必須 解説
1 送受信モデル(Generic)(図中の Generic B 必須 送受信モデル(Generic)を作成する
2 受信するデータを格納するためのクラス(独自モデル)(図中の Data B 必須 受信するデータを格納するためのクラスを作成する
3 データ変換クラス(図中の Decoder 必須 受信側のデータ変換クラス(Decoder)を作成する
4 処理結果を格納するクラス(図中の Result B 任意 処理結果を格納するクラスを作成する
5 データ処理クラス(図中の Procedure 必須 受信側のデータ処理クラス(Procedure)を作成する
6 マッピング設定(図中の Mapping Table 必須 マッピング設定を作成する
また、受信したいデータが送信側から送信されるタイミングを示す以下のキー情報を、送信側のマッピング設定などから入手してください。
下記の例では、「データを送る側の実装 」で作成したデータを受信するための元となる資材を記載しています。
  1. 送信する「独自モデル」の完全修飾子
    例) jp.co.intra_mart.module_name.function_name.propagation.SenderModuleData
  2. データの操作種別
    例) DATA_CREATED
  3. 送信側が送る「送受信モデル(Generic)」のパラメータ名と型情報
    例) jp.co.intra_mart.module_name.function_name.propagation.generic.SampleGenericData
    パラメータ名
    resourceId String
    url String
  4. 送信側が受け取る「処理結果を格納するクラス」のパラメータ名と型情報
    送信側が処理結果を要求していない場合は不要です。
    例) jp.co.intra_mart.module_name.function_name.propagation.result.ProcResult
    パラメータ名
    success boolean

送受信モデル(Generic)を作成する

最初に、直列化したデータを受信するための「送受信モデル(Generic)」を作成します。
ただし、以下に該当する場合は、このクラスを新規に作成する必要はありません。
  • 送信されるデータが格納される、データの送信側が定義した「送受信モデル(Generic)」が IM-Propagation 内に定義されている「送受信モデル(Generic)」のいずれかのクラスで復元可能である場合、定義済みのクラスを流用できます。
    定義されている「送受信モデル(Generic)」は、「APIドキュメント - jp.co.intra_mart.foundation.propagation.model.generic 」を参照してください。
    復元可能かどうかを判定する場合は、「復元可能なクラスとは 」を参照してください。
新しい「送受信モデル(Generic)」を用意する場合は、AbstractGeneric クラスを継承して新しいクラスを作成してください。
送信側が公開している「送受信モデル(Generic)」から受信したいデータが全て格納でき、かつ、「送受信モデル(Generic)」の制約を満たすクラスを作成してください。
「送受信モデル(Generic)」の制約についての詳細は、「IM-Propagation 仕様書 」を参照してください。
package jp.co.intra_mart.module_name.function_name.propagation.generic;

import jp.co.intra_mart.foundation.propagation.model.generic.AbstractGeneric;

public class SampleGenericData extends AbstractGeneric {

    /** バージョン番号(新しく採番してください) */
    private static final long serialVersionUID = 1234567890123456789L;

    /** リソースID */
    private String resourceId;

    /** URL */
    private String url;

    public String getResourceId() {
        return resourceId;
    }

    public String getUrl() {
        return url;
    }

    public void setResourceId(final String resourceId) {
        this.resourceId = resourceId;
    }

    public void setUrl(final String url) {
        this.url = url;
    }

}

注意

AbstractGeneric クラスは Serializable インタフェースを実装しているため、serialVersionUID が必要です。
上記の値をそのまま使用せず、新しく採番してください。

受信するデータを格納するためのクラスを作成する

次に、後で作成する「受信側のデータ変換クラス(Decoder)」を通して、受信するデータを格納するためのクラス(以下、「独自モデル」)を用意します。
例えば、「送受信モデル(Generic)」において String 型で定義されたプロパティを、「独自モデル」においては URL 型として扱いたい場合、String から URL に変換処理を行うために変換後のデータを格納するためのクラスが必要になります。
package jp.co.intra_mart.module_name.function_name.propagation;

import java.net.URL;

public class ReceiverModuleData {

    /** リソースID */
    private String resourceId;

    /** URL */
    private URL url;

    public String getResourceId() {
        return resourceId;
    }

    public URL getUrl() {
        return url;
    }

    public void setResourceId(final String resourceId) {
        this.resourceId = resourceId;
    }

    public void setUrl(final URL url) {
        this.url = url;
    }

}

受信側のデータ変換クラス(Decoder)を作成する

次に、「送受信モデル(Generic)」を「独自モデル」に変換する機能を提供するクラス(以下、「データ変換クラス」)を用意します。
「データ変換クラス」を作成する際は、AbstractDecoder クラスを継承してください。
AbstractDecoder クラスの総称型は、左から「送受信モデル(Generic)」、「独自モデル」の順にクラスタイプを指定してください。
AbstractDecoder クラスを継承することで、decodegetGenericDataClass メソッドの実装が必須となります。
package jp.co.intra_mart.module_name.function_name.propagation.decoder;

import java.net.MalformedURLException;
import java.net.URL;

import jp.co.intra_mart.foundation.propagation.exception.ConvertException;
import jp.co.intra_mart.foundation.propagation.receiver.AbstractDecoder;

public class SampleDecoder extends AbstractDecoder<SampleGenericData, ReceiverModuleData> {

    /**
     * 「送受信モデル」から「独自モデル」に変換するメソッド
     * @param generic 送受信モデル
     * @return 独自モデル
     * @throws 変換に失敗した場合
     */
    @Override
    public ReceiverModuleData decode(final SampleGenericData generic) throws ConvertException {
        try {
            // 送受信モデルから独自モデルに変換
            final ReceiverModuleData data = new ReceiverModuleData();
            if (generic.getResourceId() != null) {
                data.setResourceId(generic.getResourceId());
            }
            if (generic.getUrl() != null) {
                data.setUrl(new URL(generic.getUrl()));
            }

            // 独自モデルを返却
            return data;
        } catch (final MalformedURLException e) {
            throw new ConvertException(e);
        }
    }

    /**
     * 「送受信モデル」のクラスを返却するメソッド
     * @return 送受信モデルのクラス
     */
    @Override
    public Class<SampleGenericData> getGenericDataClass() {
        return SampleGenericData.class;
    }

}
実装が必要なメソッドとその説明は、以下の通りです。
  • decode メソッド

    引数から渡された「送受信モデル(Generic)」を「独自モデル」に入れ替えて返却してください。
    「送受信モデル(Generic)」と「独自モデル」がまったく同じクラスの場合は、そのまま引数の値を返却することができます。
    データの入れ替えができない状況のときや、必要なデータが格納されていなかった場合は、ConvertException 、または、ConvertException を継承した例外クラスをスローしてください。
  • getGenericDataClass メソッド

    「送受信モデル(Generic)」のクラスを返却してください。

処理結果を格納するクラスを作成する

次に、受信側が処理した結果を送り返すための「処理結果を格納するクラス」を作成します。
特に処理結果を返却しない場合はクラスを用意する必要はなく、IM-Propagation で用意されている jp.co.intra_mart.foundation.propagation.model.EmptyObject クラスで代用できます。
新しい「処理結果を格納するクラス」を用意する場合は、送信側が公開している「処理結果を格納するクラス」から復元可能なクラスを作成してください。
復元可能かどうかを判定する場合は、「復元可能なクラスとは 」を参照してください。
package jp.co.intra_mart.module_name.function_name.propagation.result;

import java.io.Serializable;

public class ProcResult implements Serializable {

    /** バージョン番号(新しく採番してください) */
    private static final long serialVersionUID = 1234567890123456789L;

    /** 成功フラグ */
    private boolean success;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(final boolean success) {
        this.success = success;
    }

}

注意

「処理結果を格納するクラス」は Serializable インタフェースを実装する必要があるため、serialVersionUID が必要です。
上記の値をそのまま使用せず、新しく採番してください。

受信側のデータ処理クラス(Procedure)を作成する

次に、「送受信モデル(Generic)」または「独自モデル」を受け取りデータ処理を行うクラス(以下、「データ処理クラス」)を用意します。
IM-Propagation は独自のセッション管理を行っており、データベースのトランザクション管理は IM-Propagation が自動的に行います。
セッション管理についての詳細は、「IM-Propagation 仕様書 」を参照してください。
「データ処理クラス」を作成する際は、AbstractProcedure クラスを継承してください。
AbstractProcedure クラスの総称型は、左から「独自モデル」、「処理結果を格納するクラス」の順にクラスタイプを指定してください。
AbstractProcedure クラスを継承することで、onReceive メソッドの実装が必須となります。
package jp.co.intra_mart.module_name.function_name.propagation.procedure;

import jp.co.intra_mart.foundation.propagation.code.EventStatus;
import jp.co.intra_mart.foundation.propagation.exception.ProcedureException;
import jp.co.intra_mart.foundation.propagation.model.ReceiveParameter;
import jp.co.intra_mart.foundation.propagation.model.ReceiveResult;
import jp.co.intra_mart.foundation.propagation.receiver.AbstractProcedure;

public class SampleProcedure extends AbstractProcedure<ReceiverModuleData, ProcResult> {

    /**
     * データを受信した際の処理を行うメソッド
     * @param parameter 受信時のパラメータ情報
     * @param data 独自モデル
     * @throws ProcedureException 処理に失敗した場合
     */
    @Override
    public ReceiveResult<ProcResult> onReceive(final ReceiveParameter parameter,
            final ReceiverModuleData data) throws ProcedureException {
        // データリクエストからデータ変換クラスを通してモデルを取得
        System.out.print(data.getUrl());
        System.out.print(data.getResourceId());

        // 処理成功を返却
        final ProcResult result = new ProcResult();
        result.setSuccess(true);
        return new ReceiveResult<ProcResult>(EventStatus.SUCCEEDED, result);
    }

}
実装が必要なメソッドとその説明は、以下の通りです。
  • onReceive メソッド

    受信したデータを処理する内容を実装してください。
    メソッドの戻り値には、ReceiveResult クラスのインスタンスを作成して返却します。
    総称型には「処理結果を格納するクラス」を指定してください。
各メソッドで返却する戻り値のインスタンスを作成する際、以下のいずれかのステータス値をコンストラクタに設定してください。
表 ステータス一覧
概要 使用例
SUCCEEDED 処理成功 処理が最後まで正常に終了したことを示す目的で使用します。
FAILED 処理失敗 処理が途中で失敗したことを示す目的で使用します。 例外発生時と同様です。
各メソッド内で処理に失敗し例外をスローする場合は ProcedureException、または、ProcedureException を継承した例外クラスをスローしてください。

コラム

  1. SUCCEEDEDFAILED 以外のステータス値は、IM-Propagation マネージャ内部で使用します。
    明示的には使用しません。
  2. 「処理結果を格納するクラス」を作成せず、特に処理結果を返さない場合は、最後の ReceiveResult インスタンスの返却を以下のように実装することができます。
    return new ReceiveResult<EmptyObject>(EventStatus.SUCCEEDED);
    

注意

onReceive メソッド内でデータベース以外(ファイルやメモリなど)の更新・削除操作を行う場合は、データベースとは別のトランザクション管理を実装する必要があります。

マッピング設定を作成する

次に、ここまで作成した「送受信モデル(Generic)」「データ変換クラス」「データ処理クラス」を紐付けるためのマッピング設定を作成します。
ファイル名の最初にはモジュールIDを含めるなど、他のモジュールが提供している設定ファイルと衝突しないようにしてください。
マッピング設定は、以下のような形式で記述します。
設定ファイルリファレンス - IM-Propagation 受信側設定 」も合わせて参照してください。
パス WEB-INF/conf/propagation-receivers-config/{任意のファイル名}.xml

<?xml version="1.0" encoding="UTF-8"?>
<propagation-receivers-config xmlns="http://www.intra-mart.jp/propagation/receivers-config"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.intra-mart.jp/propagation/receivers-config propagation-receivers-config.xsd">
  <receiver source="jp.co.intra_mart.module_name.function_name.propagation.SenderModuleData" operationType="DATA_CREATED">
    <decoder class="jp.co.intra_mart.module_name.function_name.propagation.decoder.SampleDecoder" />
    <procedure class="jp.co.intra_mart.module_name.function_name.propagation.procedure.SampleProcedure" />
  </receiver>
</propagation-receivers-config>

注意

ファイル名は、他のモジュールが提供しているものと重複しないようにするために、モジュールIDを接頭子にするなどの対策を行ってください。
例) receiver_module-sample_data.xml
設定が必要なタグとその説明は、以下の通りです。
  • receiver タグ

    source 属性には、データを送信する側が指定した「独自モデル」、または、「送受信モデル(Generic)」のパッケージ名を含むクラス名(完全修飾子)を指定します。
    受信側のクラス名ではありませんので注意してください。
    例えば、送信側が定義した SenderModuleData クラスのデータを受信したい場合は、SenderModuleData のクラス名を指定します。キーとして使用されるだけですので、この場合でも送信側モジュールとの依存関係は必要ありません。
    operationType 属性には、データを送信する側が指定した「データの操作種別」を指定します。
    例えば、送信側が定義した SenderModuleData クラスのデータが、DATA_CREATED の「データの操作種別」で送信される場合、受信側も同じ値 DATA_CREATED を指定します。
  • decoder タグ

    class 属性には、「データ変換クラス」のパッケージ名を含むクラス名(完全修飾子)を指定します。
  • procedure タグ

    class 属性には、「データ処理クラス」のパッケージ名を含むクラス名(完全修飾子)を指定します。

コラム

「データ変換クラス」や「データ処理クラス」に渡すことができる独自のパラメータ文字列を指定することができます。指定は任意です。

データを受信する

各資材をアプリケーションサーバ内に配置した後、受信対象のデータが送信されるよう操作を行ってください。
正しく設定が行われていれば、「データ処理クラス」の onReceive メソッドが呼び出され、処理が行われます。
例えばサンプル(SampleProcedure)の場合、受信したクラス内に含まれる urlresourceId の内容がコンソールに出力されます。
送信操作を行っても正しく受信できない場合は、以下の点を確認してください。
  • マッピング設定の記載が間違っていないか。
  • 「送受信モデル(Generic)」が、送信側が定義するクラスから復元可能かどうか。
  • 「データ変換クラス」が、AbstractDecoder クラスを継承しているか。
  • 「データ処理クラス」が、AbstractProcedure クラスを継承しているか。

追加情報

「データ変換クラス」「データ処理クラス」の初期パラメータを設定する

「IM-Propagation 受信側設定」の decoder タグ内、および、procedure タグ内に paramsparam タグを記述することで、「データ変換クラス」や「データ処理クラス」に渡すことができる独自のパラメータ文字列を指定することができます。
この設定により、同一の「データ変換クラス」や「データ処理クラス」で動的に変化させたいロジック・設定値がある場合などに、個別にクラスを分ける必要がなくなり、汎用性を向上させることができます。
<?xml version="1.0" encoding="UTF-8"?>
<propagation-receivers-config xmlns="http://www.intra-mart.jp/propagation/receivers-config"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.intra-mart.jp/propagation/receivers-config propagation-receivers-config.xsd">
  <receiver source="jp.co.intra_mart.module_name.function_name.propagation.SenderModuleData" operationType="DATA_CREATED">
    <decoder class="jp.co.intra_mart.module_name.function_name.propagation.decoder.SampleDecoder">
      <params>
        <param key="no-resource-id">sampleValue1</param>
        <param key="no-url">sampleValue2</param>
      </params>
    </decoder>
    <procedure class="jp.co.intra_mart.module_name.function_name.propagation.procedure.SampleProcedure">
      <params>
        <param key="update-keys">key1</param>
        <param key="update-keys">key2</param>
      </params>
    </procedure>
  </receiver>
</propagation-receivers-config>
設定が必要なタグとその説明は、以下の通りです。
  • params タグ

    param タグの親タグです。
    このタグ内に複数の param タグを記述することで、複数のパラメータ値を引き渡すことができます。
  • param タグ

    key 属性にパラメータ文字列を取得するためのキー、タグ内にパラメータ文字列を記述してください。
    キーは重複可能で、取得時に同一のキーで指定された全てのパラメータ文字列を取得できます。
    キーやパラメータ文字列を取得する場合は、「データ変換クラス」と「データ処理クラス」内で super#getParamValue()super#getParamValues()super#getParamKeys() メソッドを使用してください。
    各メソッドについての詳細は、「APIドキュメント - AbstractDecoder 」「APIドキュメント - AbstractSessionableProcedure 」を参照してください。
例えば、「データ変換クラス」上では以下のようにパラメータ値を取得して、処理を分岐できます。
package jp.co.intra_mart.module_name.function_name.propagation.decoder;

import java.net.MalformedURLException;
import java.net.URL;

import jp.co.intra_mart.foundation.propagation.exception.ConvertException;
import jp.co.intra_mart.foundation.propagation.receiver.AbstractDecoder;

public class SampleDecoder extends AbstractDecoder<SampleGenericData, ReceiverModuleData> {

    /**
     * 「送受信モデル」から「独自モデル」に変換するメソッド
     * @param generic 送受信モデル
     * @return 独自モデル
     * @throws 変換に失敗した場合
     */
    @Override
    public ReceiverModuleData decode(final SampleGenericData generic) throws ConvertException {
        try {
            // 送受信モデルから独自モデルに変換
            final ReceiverModuleData data = new ReceiverModuleData();
            if (generic.getResourceId() != null && !"true".equals(getParamValue("no-resource-id"))) {
                data.setResourceId(generic.getResourceId());
            }
            if (generic.getUrl() != null && !"true".equals(getParamValue("no-url"))) {
                data.setUrl(new URL(generic.getUrl()));
            }

            // 独自モデルを返却
            return data;
        } catch (final MalformedURLException e) {
            throw new ConvertException(e);
        }
    }

    /**
     * 「送受信モデル」のクラスを返却するメソッド
     * @return 送受信モデルのクラス
     */
    @Override
    public Class<SampleGenericData> getGenericDataClass() {
        return SampleGenericData.class;
    }

}
「データ処理クラス」内でも同様に、すべてのメソッド内で使用できます。

データベース以外の操作を行う「データ処理クラス」の実装

データベースのトランザクション管理は IM-Propagation が自動的に行いますが、データベース以外のデータ操作を行う場合は、データの受信側が独自にトランザクション管理を行う必要があります。
例えばファイル操作の場合、自身のモジュール側の処理が成功したとしても、他のモジュールで処理が失敗してしまった場合は、それまでの操作を戻す(ロールバック)処理が必要になります。
このような独自のトランザクション処理を含む「データ処理クラス」を作成する際は、AbstractProcedure ではなく AbstractSessionableProcedure クラスを継承してください。
AbstractSessionableProcedure クラスの総称型は、左から「独自モデル」、「処理結果を格納するクラス」の順にクラスタイプを指定してください。
AbstractSessionableProcedure クラスを継承することで、onInitializeonReceiveonPrepareonDecide、および、onAbort メソッドの実装が必須となります。
package jp.co.intra_mart.module_name.function_name.propagation.procedure;

import jp.co.intra_mart.foundation.propagation.code.EventStatus;
import jp.co.intra_mart.foundation.propagation.exception.ProcedureException;
import jp.co.intra_mart.foundation.propagation.model.AbortParameter;
import jp.co.intra_mart.foundation.propagation.model.AbortResult;
import jp.co.intra_mart.foundation.propagation.model.DecideParameter;
import jp.co.intra_mart.foundation.propagation.model.DecideResult;
import jp.co.intra_mart.foundation.propagation.model.EmptyObject;
import jp.co.intra_mart.foundation.propagation.model.InitializeParameter;
import jp.co.intra_mart.foundation.propagation.model.InitializeResult;
import jp.co.intra_mart.foundation.propagation.model.PrepareParameter;
import jp.co.intra_mart.foundation.propagation.model.PrepareResult;
import jp.co.intra_mart.foundation.propagation.model.ReceiveParameter;
import jp.co.intra_mart.foundation.propagation.model.ReceiveResult;
import jp.co.intra_mart.foundation.propagation.receiver.AbstractSessionableProcedure;

public class SampleProcedure extends AbstractSessionableProcedure<ReceiverModuleData, EmptyObject> {

    /**
     * セッションが開始した際の処理を行うメソッド
     * @param parameter 受信時のパラメータ情報
     * @throws ProcedureException 処理に失敗した場合
     */
    @Override
    public InitializeResult onInitialize(final InitializeParameter parameter) throws ProcedureException {
        // 一時データ格納領域の初期化
        return new InitializeResult(EventStatus.NOT_AFFECTED);
    }

    /**
     * データを受信した際の処理を行うメソッド
     * @param parameter 受信時のパラメータ情報
     * @param data 独自モデル
     * @throws ProcedureException 処理に失敗した場合
     */
    @Override
    public ReceiveResult<EmptyObject> onReceive(final ReceiveParameter parameter,
            final ReceiverModuleData data) throws ProcedureException {
        // onInitialize からの変更を一時データとして管理して、いつでもロールバックできるようにする
        return new ReceiveResult<EmptyObject>(EventStatus.NOT_AFFECTED);
    }

    /**
     * セッションが確定する前段階の処理を行うメソッド
     * @param parameter 受信時のパラメータ情報
     * @throws ProcedureException 処理に失敗した場合
     */
    @Override
    public PrepareResult onPrepare(PrepareParameter parameter) throws ProcedureException {
        // トランザクションが確定してデータが更新できるかどうかを判定
        // SUCCEEDED を返す場合は、次に onDecide または onAbort が呼び出されるまでロックをかけ、
        // データの衝突が起こらないよう (onDecide で必ず成功するよう) 対処する
        return new PrepareResult(EventStatus.NOT_AFFECTED);
    }

    /**
     * セッションが確定した際の処理を行うメソッド
     * @param parameter 受信時のパラメータ情報
     * @throws ProcedureException 処理に失敗した場合
     */
    @Override
    public DecideResult onDecide(final DecideParameter parameter) throws ProcedureException {
        // onPrepare が呼び出された時点での一時データを確定して本更新をかける
        return new DecideResult(EventStatus.NOT_AFFECTED);
    }

    /**
     * セッションが中断した際の処理を行うメソッド
     * @param parameter 受信時のパラメータ情報
     * @throws ProcedureException 処理に失敗した場合
     */
    @Override
    public AbortResult onAbort(final AbortParameter parameter) throws ProcedureException {
        // onInitiaize から行われた一時データへの変更を破棄
        return new AbortResult(EventStatus.NOT_AFFECTED);
    }

}
実装が必要なメソッドとその説明は、以下の通りです。
  • onInitialize メソッド

    「データ処理クラス」の初期化処理を実装してください。
    メソッドの戻り値には、InitializeResult クラスのインスタンスを作成して返却します。
  • onReceive メソッド

    受信したデータを処理する内容を実装してください。
    メソッドの戻り値には、ReceiveResult クラスのインスタンスを作成して返却します。
    総称型には「処理結果を格納するクラス」を指定してください。
  • onPrepare メソッド

    「データ処理クラス」内でのデータ処理を確定する準備の処理を実装してください。
    メソッドの戻り値には、PrepareResult クラスのインスタンスを作成して返却します。
    このメソッドは、onDecide メソッドが呼び出される前に、コミットが可能かどうかの問い合わせに使用されます。
  • onDecide メソッド

    「データ処理クラス」内でのデータ処理を確定する(コミット)処理を実装してください。
    メソッドの戻り値には、DecideResult クラスのインスタンスを作成して返却します。
  • onAbort メソッド

    「データ処理クラス」内でのデータ処理を元に戻す(ロールバック)処理を実装してください。
    メソッドの戻り値には、AbortResult クラスのインスタンスを作成して返却します。
例えば、ファイルに受信したデータを書き込む処理を実装する場合は、以下のような処理の流れになります。
  1. onInitialize メソッドで、テンポラリファイルを書き込む準備を行います(ディレクトリの作成など)。
  2. onReceive メソッドで、テンポラリファイルを作成し、受信したデータを書き込みます。
  3. onPrepare メソッドで、他のスレッドから本番データファイルへの変更を阻止するためのロックを取得します。
  4. onDecide メソッドで、テンポラリファイルの内容を本番データファイルへ書き込みます。
    その後、テンポラリファイルを破棄し、本番データファイルのロックを解除します。
  5. onAbort メソッドで、テンポラリファイルを破棄します。
    本番データファイルのロックが行われている場合は、ロックを解除します。