Web サービスクライアントの ServiceLocator: デザインの詳細

ここでは、java.net 主催の bpcatalog プロジェクトで提供している、Web サービスアプリケーションのクライアントとして機能する J2EE プラットフォーム (Java[tm] 2 Platform, Enterprise Edition) コンポーネントを例に対処法を説明します。 このアプリケーションは、J2EE コンポーネントが Web サービスを呼び出す方法を示す具体例です。そのデザインでサービスロケータパターンを適用するように拡張されています。このアプリケーションは、別のアプリケーションの一部として配備されている Web サービスにアクセスするサーブレットコンポーネントを示しています。基本的には、この考え方は、Web サービスにアクセスする必要がある、どの J2EE コンポーネント (サーブレット、JSP[tm] ページ、EJB[tm] コンポーネント) でも同じです。

このアプリケーションの主要要素は以下のとおりです。
このアプリケーションは、配備されている Web サービス (別のアプリケーション) にアクセスします。このクライアントは J2EE アプリケーション (この場合は Web アプリケーションの WAR ファイル) であるため、その web.xml ファイルでサービス参照を指定する必要があります。web.xml からのコードの抜粋を、次に示します。

<service-ref>
  <description>Schema defined Purchase Order Service Client</description>
  <service-ref-name>service/SchemaDefinedPurchaseOrderService</service-ref-name>
  <service-interface>
 com.sun.j2ee.blueprints.docoriented.client.objectposervice.SchemaDefinedPurchaseOrderService 
  </service-interface>
  <wsdl-file>WEB-INF/wsdl/SchemaDefinedPurchaseOrderService.wsdl</wsdl-file>
 <jaxrpc-mapping-file>WEB-INF/schemadefinedpurchaseorderservice-mapping.xml</jaxrpc-mapping-file>
  <service-qname xmlns:servicens="urn:SchemaDefinedPurchaseOrderService">servicens:SchemaDefinedPurchaseOrderService</service-qname>
</service-ref> 


コード例 1: web.xml 配備記述子におけるサービス参照

サービス参照を含めるほか、クライアントコードがルックアップできるよう、アプリケーションは配備時にその service-ref を JNDI 名にバインドする必要があります。サービスロケータパターンを使用、実装する主なクラスを見てみます。

SchemaPOServiceBD.java

SchemaPOServiceBD.java クラスのコードから見てみましょう。このクラスは、サービスロケータを使用します。このクラスには、Web サービスにアクセスするために呼び出され、委託として機能するメソッドが 1 つだけあります。このクラスには、ビジネス委託パターンが実装されています。この submitPO メソッドで重要なのは、サービスロケータを使用している部分です。サービスロケータを使用して、Web サービスに対する参照を取得してから、Web サービスを呼び出します。

public class SchemaPOServiceBD {
  private ServiceLocator serviceLocator;

  public SchemaPOServiceBD(){    
        serviceLocator = new ServiceLocator();  
    }

  public String submitPO(com.sun.j2ee.blueprints.docoriented.client.PurchaseOrder po) throws RequestHandlerException {
       
    try {      
      SchemaDefinedPurchaseOrderServiceSEI port = (SchemaDefinedPurchaseOrderServiceSEI)         
      serviceLocator.getServicePort(JNDINames.SCHEMA_SERVICE_REF, SchemaDefinedPurchaseOrderServiceSEI.class);
                     
      // エンドポイントに送信する order のサービス型にPO オブジェクトを変換
      ...    

      String ret = port.submitPO(order);
      return ret;
    } catch ...
     ....
  }
}

ServiceLocator.java

次に ServiceLocator.java クラスを見てみます。ここでわかるように、Web サービスへの参照を取得するためのサポートが追加されていることを除けば、実装はほかのリソースに対するサービスロケータのものと似ています。サービスロケータには、サービス参照を取得するためのルックアップコードがすべて含まれているため、クラスはこのサービスロケータを利用し、別の多数の場所にこのルックアップコードにコピーする手間を回避できます。これは、アプリケーションのコードの整理に役立ちます。

import javax.naming.*;
import java.rmi.Remote;
import javax.xml.rpc.*;

/**
 * Implements Service Locator pattern for Web services
 */
public class ServiceLocator {
   
    private transient InitialContext ic;

    public ServiceLocator() throws ServiceLocatorException  {
        try {
            setInitialContext();
        } catch (Exception e) {
            throw new ServiceLocatorException(e);
        }
    }

    private void setInitialContext() throws javax.naming.NamingException {
      ic = new InitialContext();
    }

    /**
     * Service class acts as a factory of the Dynamic proxy for the target service endpoint.
     * @see java.xml.rpc.Service.java
     * @return the Service instance
     */
    public Remote getServicePort(String jndiName, Class className) throws ServiceLocatorException {
        try {
            if (ic == null) setInitialContext();
            Service service = (Service) ic.lookup(jndiName);
            return service.getPort(className);
        } catch (Exception e) {
            throw new ServiceLocatorException("ServiceLocator can not lookup jndiName=" + jndiName + " and className=" + className,  e);
        }
    } 
}

ServiceLocatorException.java

次に ServiceLocatorException.java クラスを見てみます。この例外で RuntimeException を拡張するようにしていることに注目してください。ネーミングディレクトリでのリソースのルックアップ中にエラーが発生した場合、ユーザーにとってそのエラーは回復不能な例外になるため、そうしたエラーは、妨げられないシステム例外として扱うようにしています。また、例外の連鎖も使用していることに注意してください。サービスロケータを使用するこの J2EE クライアントアプリケーション例では、web.xml で主サーブレットがサーブレットエラーページのマッピング機構を使用し、システムエラーメッセージを出力する JSP エラーページに、この例外とすべての実行時例外をマッピングしています。

package com.sun.j2ee.blueprints.docoriented.client;

public class ServiceLocatorException extends RuntimeException {
    public ServiceLocatorException() {}
    public ServiceLocatorException(String msg) { super(msg); }
    public ServiceLocatorException(String msg, Throwable cause) { super(msg, cause); }
    public ServiceLocatorException(Throwable cause) { super(cause); }
}


© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.