43.3. 論理ハンドラーでのメッセージの処理

概要

通常のメッセージ処理は、handleMessage() メソッドによって処理されます。

handleMessage() メソッドは、メッセージボディーおよびメッセージコンテキストに保存されたプロパティーへのアクセスを提供する LogicalMessageContext オブジェクトを受け取ります。

メッセージ処理の継続方法に応じて、handleMessage() メソッドは true または false のいずれかを返します。例外を出力することもできます。

メッセージデータの取得

論理メッセージハンドラーに渡される LogicalMessageContext オブジェクトにより、コンテキストの getMessage() メソッドを使用してメッセージボディーにアクセスできます。例43.2「論理ハンドラーでメッセージペイロードを取得する方法」に示した getMessage() メソッドは、LogicalMessage オブジェクトとしてメッセージペイロードを返します。

例43.2 論理ハンドラーでメッセージペイロードを取得する方法

LogicalMessagegetMessage

LogicalMessage オブジェクトを取得したら、それを使用してメッセージ本文を操作できます。例43.3「論理メッセージホルダー」 に示す LogicalMessage インターフェイス、実際のメッセージ本文を操作するためのゲッターとセッターがあります。

例43.3 論理メッセージホルダー

LogicalMessageSourcegetPayloadObjectgetPayloadJAXBContextcontextsetPayloadObjectpayloadJAXBContextcontextsetPayloadSourcepayload

重要

メッセージペイロードの内容は、使用中のバインディングのタイプによって決まります。SOAP バインディングは、メッセージの SOAP 本文へのアクセスのみを許可します。XML バインディングにより、メッセージ本文全体にアクセスできます。

メッセージ本文を XML オブジェクトとして操作する

論理メッセージのゲッターとセッターの 1 つのペアは、メッセージペイロードを javax.xml.transform.dom.DOMSource オブジェクトとして操作します。

パラメーターのない getPayload() メソッドは、DOMSource オブジェクトとしてメッセージペイロードを返します。返されるオブジェクトは、実際のメッセージペイロードです。返されたオブジェクトに変更を加えると、メッセージ本文がすぐに変更されます。

単一の Source オブジェクトを取る setPayload() メソッドを使用して、メッセージのボディーを DOMSource オブジェクトに置き換えることができます。

メッセージ本文を JAXB オブジェクトとして操作する

ゲッターとセッターのもう 1 つのペアを使用すると、メッセージペイロードを JAXB オブジェクトとして操作できます。JAXBContext オブジェクトを使用して、メッセージペイロードを JAXB オブジェクトに変換します。

JAXB オブジェクトを使用するには、次のようにします。

  1. メッセージボディーのデータ型を管理できる JAXBContext オブジェクトを取得します。

    JAXBContext オブジェクト作成の詳細は、39章JAXBContext オブジェクトの使用 を参照してください。

  2. 例43.4「メッセージ本文を JAXB オブジェクトとして取得する」 に示すようにメッセージ本文を取得します。

    例43.4 メッセージ本文を JAXB オブジェクトとして取得する

    JAXBContext jaxbc = JAXBContext(myObjectFactory.class);
    Object body = message.getPayload(jaxbc);
  3. 返されたオブジェクトを適切なタイプにキャストします。
  4. 必要に応じてメッセージ本文を操作します。
  5. 例43.5「JAXB オブジェクトを使用したメッセージ本文の更新」 に示すように、更新されたメッセージ本文をコンテキストに戻します。

    例43.5 JAXB オブジェクトを使用したメッセージ本文の更新

    message.setPayload(body, jaxbc);

コンテキストプロパティーの操作

論理ハンドラーに渡される論理メッセージコンテキストは、アプリケーションのメッセージコンテキストのインスタンスであり、そこに格納されているすべてのプロパティーにアクセスできます。ハンドラーは、APPLICATION スコープが設定されたプロパティーと HANDLER スコープが設定されたプロパティーの両方にアクセスできます。

アプリケーションのメッセージコンテキストと同様に、論理メッセージコンテキストは Java Map のサブクラスです。コンテキストに保存されたプロパティーにアクセスするには、Map インターフェイスから継承された get() メソッドと put() メソッドを使用します。

デフォルトでは、論理ハンドラー内からメッセージコンテキストで設定したプロパティーには、HANDLER のスコープが割り当てられます。アプリケーションコードがプロパティーにアクセスできるようにするには、コンテキストの setScope() メソッドを使用して、プロパティーのスコープを明示的に APPLICATION. に設定する必要があります。

メッセージコンテキストでのプロパティーの操作の詳細については、「コンテキストを理解する」 を参照してください。

メッセージの方向を決定する

多くの場合、メッセージがハンドラーチェーンを通過する方向を知ることが重要です。たとえば、着信要求からセキュリティートークンを取得し、発信応答にセキュリティートークンを添付するとします。

メッセージの方向は、メッセージコンテキストのアウトバウンドメッセージプロパティーに保存されます。例43.6「SOAP メッセージコンテキストからのメッセージの方向の取得」 に示すように、MessageContext.MESSAGE_OUTBOUND_PROPERTY キーを使用して、メッセージコンテキストからアウトバウンドメッセージプロパティーを取得します。

例43.6 SOAP メッセージコンテキストからのメッセージの方向の取得

Boolean outbound;
outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

このプロパティーは Boolean オブジェクトとして保存されます。オブジェクトの booleanValue() メソッドを使用して、プロパティーの値を決定できます。プロパティーが true に設定されている場合、メッセージはアウトバウンドです。プロパティーが false に設定されている場合、メッセージはインバウンドです。

戻り値の決定

handleMessage() メソッドがそのメッセージ処理をどのように完了するかが、メッセージ処理の実施方法に直接的な影響を及ぼします。次のいずれかのアクションを実行することで完了できます。

  1. true を返す - メッセージ処理を正常に続行する必要があることを示す true シグナルを Apache CXF ランタイムに返します。次のハンドラーがある場合は、その handleMessage() が呼び出されます。
  2. false を返す - 通常のメッセージ処理を停止する必要がある false シグナルを Apache CXF ランタイムに返します。ランタイムがどのように進行するかは、現在のメッセージ に使用されているメッセージ交換パターンによって異なります。

    要求/応答メッセージ交換の場合は、次のことが起こります。

    1. メッセージ処理の方向が逆になります。

      たとえば、要求がサービスプロバイダーによって処理されている場合、メッセージはサービスの実装オブジェクトへの進行を停止します。代わりに、リクエストを発信したコンシューマーに返すために、バインディングに向けて送り返されます。

    2. 新しい処理方向でハンドラーチェーンに沿って存在するメッセージハンドラーには、チェーン内で存在する順序で handleMessage() メソッドが呼び出されます。
    3. メッセージがハンドラーチェーンの最後に到達すると、メッセージがディスパッチされます。

      一方向のメッセージ交換の場合は、次のことが起こります。

    4. メッセージ処理が停止します。
    5. これまで呼び出されたすべてのメッセージハンドラーには、その close() メソッドが呼び出されます。
    6. メッセージが送信されます。
  3. ProtocolException 例外を出力する -ProtocolException 例外、またはこの例外のサブクラスを出力すると、障害メッセージ処理が開始されていることを Apache CXF ランタイムに通知します。ランタイムがどのように進行するかは、現在のメッセージ に使用されているメッセージ交換パターンによって異なります。

    要求/応答メッセージ交換の場合は、次のことが起こります。

    1. ハンドラーがまだ障害メッセージを作成していない場合、ランタイムはメッセージを障害メッセージでラップします。
    2. メッセージ処理の方向が逆になります。

      たとえば、要求がサービスプロバイダーによって処理されている場合、メッセージはサービスの実装オブジェクトへの進行を停止します。代わりに、リクエストを発信したコンシューマーに返すために、バインディングに向けて送り返されます。

    3. 新しい処理方向でハンドラーチェーンに沿って存在するメッセージハンドラーには、チェーン内で存在する順序で handleFault() メソッドが呼び出されます。
    4. 障害メッセージがハンドラーチェーンの最後に到達すると、ディスパッチされます。

      一方向のメッセージ交換の場合は、次のことが起こります。

    5. ハンドラーがまだ障害メッセージを作成していない場合、ランタイムはメッセージを障害メッセージでラップします。
    6. メッセージ処理が停止します。
    7. これまで呼び出されたすべてのメッセージハンドラーには、その close() メソッドが呼び出されます。
    8. 障害メッセージが送信されます。
  4. その他のランタイム例外を出力する -ProtocolException 例外以外のランタイム例外を出力すると、メッセージ処理が停止することを Apache CXF ランタイムに通知します。これまで呼び出されたすべてのメッセージハンドラーには close() メソッドが呼び出され、例外がディスパッチされます。メッセージが要求/応答メッセージ交換の一部である場合、例外がディスパッチされ、要求を発信したコンシューマーに返されます。

例43.7「論理メッセージハンドラーメッセージ処理」に、サービスコンシューマーによって使用される論理メッセージハンドラーの handleMessage() メッセージの実装を示します。リクエストは、サービスプロバイダーに送信される前に処理されます。

例43.7 論理メッセージハンドラーメッセージ処理

public class SmallNumberHandler implements LogicalHandler<LogicalMessageContext>
{
    public final boolean handleMessage(LogicalMessageContext messageContext)
    {
        try
        {
            boolean outbound = (Boolean)messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

            if (outbound)
            {
                LogicalMessage msg = messageContext.getMessage();

                JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
                Object payload = msg.getPayload(jaxbContext);
                if (payload instanceof JAXBElement)
                {
                    payload = ((JAXBElement)payload).getValue();
                }

                if (payload instanceof AddNumbers)
                {
                    AddNumbers req = (AddNumbers)payload;

                    int a = req.getArg0();
                    int b = req.getArg1();
                    int answer = a + b;

                    if (answer < 20)
                    {
                      AddNumbersResponse resp = new AddNumbersResponse();
                      resp.setReturn(answer);
                      msg.setPayload(new ObjectFactory().createAddNumbersResponse(resp),
                                                      jaxbContext);

                      return false;
                    }
                }
                else
                {
                   throw new WebServiceException("Bad Request");
                }
            }
            return true;
        }
        catch (JAXBException ex)
        {
            throw new ProtocolException(ex);
        }
    }
...
}

例43.7「論理メッセージハンドラーメッセージ処理」 のコードは、以下を行います。

メッセージがアウトバウンド要求であるかどうかを確認します。

メッセージがアウトバウンド要求である場合、ハンドラーは追加のメッセージ処理を行います。

メッセージコンテキストからメッセージペイロードの LogicalMessage 表現を取得します。

実際のメッセージペイロードを JAXB オブジェクトとして取得します。

リクエストが正しいタイプであることを確認します。

そうである場合、ハンドラーはメッセージの処理を続行します。

合計の値をチェックします。

しきい値の 20 未満の場合、応答を作成してクライアントに返します。

応答を作成します。

false を返し、メッセージ処理を停止してクライアントに応答を返します。

メッセージのタイプが正しくない場合、ランタイム例外を出力します。

この例外はクライアントに返されます。

メッセージがインバウンド応答であるか、合計がしきい値を満たさない場合、true を返します。

メッセージ処理は正常に続行されます。

JAXB マーシャリングエラーが発生した場合、ProtocolException を出力します。

例外は、現在のハンドラーとクライアント間でハンドラーの handleFault() メソッドによって処理された後にクライアントに渡して戻されます。