Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (日本語) » SQL Anywhere サーバ - プログラミング » SQL Anywhere データ・アクセス API » SQL Anywhere Web サービス

 

チュートリアル:JAX-WS でのデータ型の使用

次のチュートリアルでは、Java API for XML Web Services (JAX-WS) を使用して Web サービスにアクセスする方法を示します。

前述の JAX-WS のチュートリアルをすでに終了している場合は、このチュートリアルの一部の手順はすでに実行済みです。

チュートリアルを始める前に、Sun から入手可能な JAX-WS ツールが必要です。このパッケージがシステムにインストールされていない場合は、JAX-WS ツールをダウンロードしてインストールしてください。JAX-WS ツールをダウンロードするには、[external link] http://java.sun.com/webservices/ を参照してください。JAX-WS のリンクをクリックすると、[external link] Java API for XML Web Services のページが開きます。Download Now リンクをクリックします。ソフトウェア・パッケージをダウンロードしたら、それをシステムにインストールします。

このサンプルは、JAX-WS 2.1.3 for Windows を使用して開発されました。

JAX-WS からアクセスできる SQL Anywhere SOAP Web サービスは、CONCRETE フォーマットとして宣言する必要があります。

♦  SOAP および DISH サービスを作成するには、次の手順に従います。
  1. コマンド・プロンプトで、次のコマンドを実行して、パーソナル Web サーバを起動します。samples-dir をサンプル・データベースの実際のロケーションと置き換えます。-xs http(port=80) オプションは、HTTP 要求をポート 80 で受け入れるようにデータベース・サーバに指示します。すでにポート 80 で稼働している Web サーバがある場合は、このチュートリアルには 8080 などの別のポート番号を使用してください。

    dbeng11 -xs http(port=80) samples-dir\demo.db
  2. Interactive SQL を起動し、DBA として SQL Anywhere サンプル・データベースに接続します。次の文を実行します。

    1. Employees テーブルの一部のカラムをリストするストアド・プロシージャを定義します。

      CREATE PROCEDURE ListEmployees()
      RESULT (
       EmployeeID            INTEGER,
       Surname               CHAR(20),
       GivenName             CHAR(20),
       StartDate             DATE,
       TerminationDate       DATE )
      BEGIN
        SELECT EmployeeID, Surname, GivenName, 
          StartDate, TerminationDate 
        FROM Employees;
      END;
    2. このストアド・プロシージャを呼び出す SOAP サービスを定義します。

      CREATE SERVICE "WS/EmployeeList2"
      TYPE 'SOAP'
      FORMAT 'CONCRETE' EXPLICIT ON
      DATATYPE OUT
      AUTHORIZATION OFF
      SECURE OFF
      USER DBA
      AS CALL ListEmployees();

      EXPLICIT 句は、CONCRETE 型の SOAP または DISH サービスでのみ使用できます。この例の EXPLICIT ON は、対応する DISH サービスで EmployeeList2Dataset オブジェクトを記述する XML スキーマを生成することを示します。このオプションの影響を受けるのは、生成される WSDL ドキュメントだけです。前述の JAX-WS のチュートリアルでは、EXPLICIT OFF を使用した例を紹介しました。チュートリアル:JAX-WS からの Web サービスへのアクセスを参照してください。

      DATATYPE OUT は、明示的なデータ型情報が XML 結果セットの応答で生成されることを示します。DATATYPE OFF が指定されている場合、すべてのデータは String 型になります。このオプションは、生成される WSDL ドキュメントに影響しません。

      認証はオフになっているため、ユーザ名とパスワードを入力せずにだれでもこのサービスを利用できます。このコマンドは、ユーザが DBA の場合に実行できます。この方法は簡単ですが、安全性に優れていません。

    3. SOAP サービスのプロキシとして機能し、WSDL ドキュメントを生成する DISH サービスを作成します。

      CREATE SERVICE "WSDish"
      TYPE 'DISH'
      FORMAT 'CONCRETE'
      GROUP "WS"
      AUTHORIZATION OFF
      SECURE OFF
      USER DBA;
      

      SOAP サービスと DISH サービスは、CONCRETE フォーマットである必要があります。EmployeeList2 サービスは WS グループであるため、GROUP 句が含まれます。

  3. DISH サービスにより自動的に生成される WSDL を見てみます。そのためには、Web ブラウザを開き、URL [external link] http://localhost:80/demo/WSDish にアクセスします。DISH は、ブラウザのウィンドウに表示される WSDL ドキュメントを自動生成します。

    特に、EmployeeList2Dataset オブジェクトに注目してください。このサービスのフォーマットは CONCRETE で EXPLICIT が ON になっているため、EmployeeList2Dataset オブジェクトは公開されています。この後の手順で、wsimport アプリケーションはこの情報を使用して、このサービス用の SOAP 1.1 クライアント・インタフェースを生成します。

    <s:complexType name="EmployeeList2Dataset">
    <s:sequence>
    <s:element name="rowset">
      <s:complexType>
      <s:sequence>
      <s:element name="row" minOccurs="0" maxOccurs="unbounded">
        <s:complexType>
        <s:sequence>
        <s:element minOccurs="0" maxOccurs="1" name="EmployeeID" 
            nillable="true" type="s:int" /> 
        <s:element minOccurs="0" maxOccurs="1" name="Surname" 
            nillable="true" type="s:string" /> 
        <s:element minOccurs="0" maxOccurs="1" name="GivenName" 
            nillable="true" type="s:string" /> 
        <s:element minOccurs="0" maxOccurs="1" name="StartDate" 
            nillable="true" type="s:date" /> 
        <s:element minOccurs="0" maxOccurs="1" name="TerminationDate" 
            nillable="true" type="s:date" /> 
        </s:sequence>
        </s:complexType>
      </s:element>
      </s:sequence>
      </s:complexType>
    </s:element>
    </s:sequence>
    </s:complexType>
♦  Web サービス用の JAX-WS インタフェースを生成するには、次の手順に従います。
  1. この例では、Java API for XML Web Services (JAX-WS) と Sun Java 1.6.0 JDK は C: ドライブにインストールされています。JAX-WS バイナリと JDK バイナリがパスに含まれるように PATH 環境変数を設定します。バイナリは次のディレクトリにあります。

    c:\Sun\jaxws-ri\bin
    c:\Sun\SDK\jdk\bin
  2. コマンド・プロンプトで、CLASSPATH 環境変数を設定します。

    SET classpath=.;C:\Sun\jaxws-ri\lib\jaxb-api.jar
    ;C:\Sun\jaxws-ri\lib\jaxws-rt.jar
  3. 次の手順では、Web サービスを呼び出すために必要なインタフェースを生成します。

    同じコマンド・プロンプトで、新しいプロジェクト・ディレクトリを作成し、これを現在のディレクトリにします。このディレクトリで次のコマンドを実行します。

    wsimport -keep -Xendorsed "http://localhost:80/demo/WSDish"

    wsimport ツールは、指定された URL から WSDL ドキュメントを取得し、そのインタフェースを定義する Java ファイルを生成してから、Java ファイルをコンパイルします。

    keep オプションは、.java ファイルを削除しないように wsimport に指示します。このオプションが指定されない場合は、対応する .class ファイルの生成後にこれらのファイルは削除されます。これらのファイルを保存すると、インタフェースの構成の検査が簡単になります。

    Xendorsed オプションは、JAX-WS 2.1 API を JDK6 と一緒に使用できるようにします。

    このコマンドが完了すると、以下の Java ファイルと、各 Java ファイルがコンパイルされた .class ファイルを含む localhost\demo\ws というサブディレクトリ構造が作成されています。

    EmployeeList2.java
    EmployeeList2Dataset.java
    EmployeeList2Response.java
    FaultMessage.java
    ObjectFactory.java
    package-info.java
    WSDish.java
    WSDishSoapPort.java
♦  生成された JAX-WS インタフェースを使用するには、次の手順に従います。
  1. 次の Java ソース・コードを SASoapDemo2.java として保存します。このファイルが、wsimport ツールで生成された localhost サブディレクトリを含むディレクトリと同じ場所にあることを確認してください。

    // SASoapDemo2.java illustrates a web service client that
    // calls the WSDish service and prints out the data.
    
    import java.util.*;
    import javax.xml.ws.*;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import javax.xml.datatype.*;
    import localhost.demo.ws.*;
    
    public class SASoapDemo2
    {
      public static void main( String[] args )
      {
        try {
          WSDish service = new WSDish();
    
          Holder<EmployeeList2Dataset> response = 
              new Holder<EmployeeList2Dataset>();
          Holder<Integer> sqlcode = new Holder<Integer>();
                
          WSDishSoapPort port = service.getWSDishSoap();
    
          // This is the SOAP service call to EmployeeList2
          port.employeeList2( response, sqlcode );
    
          EmployeeList2Dataset result = response.value;
          EmployeeList2Dataset.Rowset rowset = result.getRowset();
    
          List<EmployeeList2Dataset.Rowset.Row> rows = rowset.getRow();
    
          String fieldType;
          String fieldName;
          String fieldValue;
          Integer fieldInt;
          XMLGregorianCalendar fieldDate;
          
          for ( int i = 0; i < rows.size(); i++ ) {
            EmployeeList2Dataset.Rowset.Row row = rows.get( i );
    
            fieldType = row.getEmployeeID().getDeclaredType().getSimpleName();
            fieldName = row.getEmployeeID().getName().getLocalPart();
            fieldInt = row.getEmployeeID().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldInt );
            
            fieldType = row.getSurname().getDeclaredType().getSimpleName();
            fieldName = row.getSurname().getName().getLocalPart();
            fieldValue = row.getSurname().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldValue );
            
            fieldType = row.getGivenName().getDeclaredType().getSimpleName();
            fieldName = row.getGivenName().getName().getLocalPart();
            fieldValue = row.getGivenName().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                 "=" + fieldValue );
            
            fieldType = row.getStartDate().getDeclaredType().getSimpleName();
            fieldName = row.getStartDate().getName().getLocalPart();
            fieldDate = row.getStartDate().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldDate );
            
            if ( row.getTerminationDate() == null ) {
              fieldType = "unknown";
              fieldName = "TerminationDate";
              fieldDate = null;
            } else {
              fieldType = 
                row.getTerminationDate().getDeclaredType().getSimpleName();
              fieldName = row.getTerminationDate().getName().getLocalPart();
              fieldDate = row.getTerminationDate().getValue();
            }
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldDate );
            System.out.println();
          }
        }
        catch (Exception x) {
          x.printStackTrace();
        }
      }
    }

    8080 のように別のポート番号を使用して Web サーバを起動する場合は、import localhost ソース行を次のように変更する必要があります。

    import localhost._8080.demo.ws.*;
  2. SASoapDemo2.java をコンパイルします。

    javac SASoapDemo2.java
  3. コンパイル済みのクラス・ファイルを実行します。

    java SASoapDemo2

    アプリケーションは Web サーバに要求を送信すると、XML 結果セット応答を受け取ります。この応答は、複数のロー・エントリを含むローセットを持つ EmployeeList2Result から構成されています。この応答には、クエリの実行結果の sqlcode も含まれています。この応答の例を次に示します。

    <tns:EmployeeList2Response>
     <tns:EmployeeList2Result xsi:type='tns:EmployeeList2Dataset'>
      <tns:rowset>
        <tns:row>...</tns:row>
    .
    .
    .
        <tns:row>...</tns:row>
       </tns:rowset>
     </tns:EmployeeList2Result>
     <tns:sqlcode>0</tns:sqlcode>
    </tns:EmployeeList2Response>

    ローセットの各ローは、次のようなフォーマットで送信されます。

    <tns:row>
       <tns:EmployeeID xsi:type="xsd:int">1751</tns:EmployeeID>
       <tns:Surname xsi:type="xsd:string">Ahmed</tns:Surname>
       <tns:GivenName xsi:type="xsd:string">Alex</tns:GivenName>
       <tns:StartDate xsi:type="xsd:date">1994-07-12-04:00</tns:StartDate>
       <tns:TerminationDate xsi:type="xsd:date">2008-04-18-04:00
           </tns:TerminationDate>
    </tns:row>

    カラム名とデータ型が含まれていることに注意してください。

    プロキシの使用

    XML メッセージ・トラフィックを記録するプロキシ・ソフトウェアを使用して、上記の応答を確認することができます。プロキシは、クライアント・アプリケーションと Web サーバの間に挿入されます。

    EmployeeList2 結果セットは、SASoapDemo2 アプリケーションによって「(型)カラム=値」のペアで表示されます。生成される出力は次のようになります。

    (Integer)EmployeeID=102
    (String)Surname=Whitney
    (String)GivenName=Fran
    (XMLGregorianCalendar)StartDate=1984-08-28-04:00
    (unknown)TerminationDate=null
    
    (Integer)EmployeeID=105
    (String)Surname=Cobb
    (String)GivenName=Matthew
    (XMLGregorianCalendar)StartDate=1985-01-01-05:00
    (unknown)TerminationDate=null
    .
    .
    .
    (Integer)EmployeeID=1740
    (String)Surname=Nielsen
    (String)GivenName=Robert
    (XMLGregorianCalendar)StartDate=1994-06-24-04:00
    (unknown)TerminationDate=null
    
    (Integer)EmployeeID=1751
    (String)Surname=Ahmed
    (String)GivenName=Alex
    (XMLGregorianCalendar)StartDate=1994-07-12-04:00
    (XMLGregorianCalendar)TerminationDate=2008-04-18-04:00

    TerminationDate カラムが送信されるのは、その値が NULL でない場合だけです。この Java アプリケーションは、TerminationDate カラムが存在しない場合、それを検出するように設計されています。この例では、終了日に NULL 以外の値が設定され、Employees テーブルの最後のローが変更されました。

    また、日付値には UTC (協定世界時) からのオフセットが含まれています。前述のサンプル・データでは、サーバは北米東部のタイムゾーンに属する場所にあります。つまり、標準時間の場合は UTC よりも 5 時間早く (-05:00)、夏時間の場合は UTC よりも 4 時間早い (-04:00) ことになります。

    SASoapDemo2 アプリケーションで使用されている Java メソッドの詳細については、java.sun.com の Web サイト ([external link] http://java.sun.com/javaee/5/docs/api/) で javax.xml.bind.JAXBElement クラスの情報を参照してください。