本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

Linux上にLSID認定システムを構築する

JavaによるLSID認定システムで生物学的データ資源を統合

Stefan Atev, Programmer, IBM
Stefan Atev氏は、Extreme Blue 2001インターンシップ・プログラムの卒業生です。SashXB Webサービスのクライアントの研究を続けてきた後、現在はLife Sciences Identifierプロジェクトに参加し、Life Sciencesデータ・ストアを実装したり、セマンティックWebテクノロジーを応用して既存のLife Sciencesデータベースの使いやすさの改善を図ったりしています。

概要: 本稿では、JavaでLSID (Life Sciences Identifier: 生命科学データ名) 認定システムを一から構築する方法を順を追って解説します。ここでは、ごくわずかなデータ・セットを用いたシステムやたんぱく質配列データベースSwiss-Protからダウンロードしてきたデータを用いたシステムをLinuxのプラットフォームに構築します。

日付:  2003年 5月 27日
レベル:  上級 この記事の原文:  英語
アクティビティー: 1137 ビュー
お気軽にご意見・ご感想をお寄せください: 


近年では、途方もなく大量の生物学的データが作成されています。生物学者や生物情報科学者なら、仕事に役立つ非常に便利な資源がネットワークのあちこちで提供されているのをご存じだろうと思いますが、こうした情報にアクセスするにはいろいろな約束ごとを覚えなければならず、生産性を消耗させることがよくあります。多分皆さんは、そのためのPerlのスクリプトを自分でいくつか書くか、あるいはそのためのコードや手順を提供してくれる人を知っているのではないかと思います。現在では、プログラマーでなく生物学者であり続けるための最後の砦は、こうしたデータの名前の付け方や検索方法といった一般的な知識を知っていることだと考えられているかもしれません。もちろん、データ識別のための一般的な知識には生物情報学の範囲を越えた価値があるわけですが、この記事では生命科学の範囲内の話に留めます。

LSID (Life Sciences Identifier: 生命科学データ名) とは、現在策定中のI3CのUniform Resource Name (URN) 仕様のことです。この仕様についてはI3Cに詳しい情報が掲載されています (リンクは参考文献参照)。LSIDは、基本的には、いろいろなデータ・ストアに分散して保存されているデータ資源を簡明に命名したり識別するための手法であり、現在使用されている命名方式の制約を克服しようというものです。

LSIDのURNによって一義的に命名されたデータを高位のソフトウェアが発見しアクセスできるようにするための合意済みのLSID解決プロトコルを実装するソフトウェア・システムにLSIDリゾルバー (LSID resolver) というものがあります。このリゾルバーの「サーバー」側のことをLSID認定システム (LSID authority) と呼んでおり、そのクライアント・スタックおよびクライアント・サンプルであるLSID LaunchPadがLSID Resolution Protocol Project (LSID解決プロトコル・プロジェクト) から提供されています。

本稿では、Java用のLSIDリゾルバー・スタックを使ってLSID認定システムを作成する方法を紹介しています。

はじめに

この記事では、認定システムの収容されるシステムで皆さんが必要な管理権限をもっているものとして話を進めます (たいていは、いくつかの作業でルート ・アクセスが必要となります)。

本稿に示す手順は、すべてRed Hat Linux 7.1とRed Hat Linux 8でテストされています。またJava JDKについては、バージョン1.3.1と1.4.0でテストしました。サーブレット環境にはJakarta Tomcat 4.1.18を使用しました。サンプル・コードはIBM WebSphere V5でも動かすことができます。

必要なソフトウェア

まず必要なものは、WebサーバーのJakarta Tomcat 4が稼働されるシステムへのアクセス権、Java2 (JDK 1.3.1以上を推奨)、並びにMySQL 3.23.xなどのデータベース・エンジンです。

必要なJavaパッケージ

Java LSIDクライアント/サーバー・スタックを利用するには、まず以下のパッケージをインストールしておく必要があります。

  • Xalan-J 2.4.1
    • xalan.jar
    • xml-apis.jar
    • xercesImpl.jar

Jakarta Tomcatのshared/libディレクトリーに .jarファイルをコピーするか、あるいはシステム・クラス・パスを介してJavaランタイム・エンジンがそれらのファイルにアクセスできるようにしてください。

テスト用にSwiss-Protデータ・セットを使ってサンプルの認定システムをセットアップしたい場合には、MySQL ABで入手できるMySQL Connector/Jディストリビューションに含まれているmysql-connector-java-x.x.x-bin.jarというファイルも必要になります (リンクは参考文献参照)。JDBCドライバーの最新バージョンは必要ありません。LGPLライセンス・バージョンの2.0.14で充分です。このモジュールは、サンプルの認定システム・サーバーがSwiss-Protデータの入っているMySQLデータベースをアクセスするときに使用されるもので、Jakarta Tomcatのshared/lib ディレクトリーに置く必要があります (あるいは、システム・クラス・パスに置くやり方でもかまいません)。


LSIDパッケージのインストール

必要なソフトウェアをダウンロードしたら、LSID Javaクライアント/サーバー・スタックの最新バージョン (本稿執筆時点でのバージョンは0.3) を入手します。 バイナリーのLSIDサーバー・ディストリビューション バイナリーのLSIDクライアント・ディストリビューション を入手し、lsid-client.jarファイルおよびlsid-server.jarファイルをJakarta Tomcatのshared/libディレクトリーにコピーします。

Java LSIDサーバー・パッケージには、完全機能版のLSID解決サービスの他に、LSID認定システムを簡単に作成するための一連のサーブレットと簡略化版のインターフェースも用意されています。


Hello World -- LSID認定システムの第一歩

先に進む前に、urn:lsid:ibm.com:hello:world というLSIDを1個だけ知っている認定システムを実装してみましょう。このLSIDは、以下の要素で構成されています。

  • ibm.com -- 発行側認定システムのドメイン
  • hello -- LSIDの名前空間
  • world -- LSIDのオブジェクトID

認定システムを最も簡単に実装する方法はcom.ibm.lsid.server.impl.SimpleAuthority クラスを拡張することです。これは、com.ibm.lsid.server.AuthorityServlet によって実装される標準的な認定システム・サーブレットが使用するクラスです。この場合、以下のメソッドを提供/オーバーライドする必要があります。

  • initAuthority
  • getKnownURIs
  • getDataLocations
  • getMetaDataLocations

この認定システムは、データやメタデータのサービスは提供せず、urn:lsid:ibm.com:hello:world のデータを読み出すことのできる場所を記述するだけです。

コードは、java-samples.tar.gz をダウンロードし、HelloWorldAuthority.javaかWARファイルのhelloworld.warを抽出することで入手できます。


リスト1. Helloのコード
                
01  package lsidsamples;
02  
03  import com.ibm.lsid.LSID;
04  import com.ibm.lsid.MalformedLSIDException;
05  import com.ibm.lsid.ExpiringResponse;
06  import com.ibm.lsid.wsdl.LSIDDataPort;
07  import com.ibm.lsid.wsdl.LSIDMetaDataPort;
08  import com.ibm.lsid.server.LSIDServiceConfig;
09  import com.ibm.lsid.server.LSIDServerException;
10  import com.ibm.lsid.server.impl.SimpleAuthority;
11  import com.ibm.lsid.server.impl.HTTPDataLocation;
12  import com.ibm.lsid.server.impl.FTPDataLocation;
13  
14  public class HelloWorldAuthority extends SimpleAuthority {
15      
16    public void initAuthority(LSIDServiceConfig config) throws LSIDServerException {
17    }
18      
19    public ExpiringResponse getKnownURIs() throws LSIDServerException {
20      try {
21        return new ExpiringResponse(
22          new LSID[] {
23            new LSID("urn:lsid:ibm.com:hello:world")
24          },
25          null
26        );
27      } catch (MalformedLSIDException ex) {
28        throw new LSIDServerException(
39          ex, 500, "This error should have never occurred"
30        );
31      }
32    }
33      
34    public LSIDMetaDataPort[] getMetaDataLocations(LSID lsid, String url) {
35      return new LSIDMetaDataPort[0];
36    }
37  
38    public LSIDDataPort[] getDataLocations(LSID lsid, String url) {
39      return new LSIDDataPort[] {
40        new HTTPDataLocation(
41          "www.ibm.com", 80, "/lsid/hello_world.txt"
42        ),
43        new FTPDataLocation(
44          "ftp.ibm.com", "/lsid/hello_world.txt"
45        )
46      };
47    }
48  }

Hello Worldの解剖

01 は、この認定システムの実装がlsidsamples パッケージに属していることを表します。行03 - 12 では、認定システムを実装するのに必要なクラスやインターフェースをインポートしています。ここでは、実装lsidsamples.HelloWorldAuthority のベースにcom.ibm.lsid.server.impl.SimpleAuthority クラスを使用しています (行14)。

16 - 17 では、認定システムの起動時に呼び出されるinitAuthority メソッドを実装しています。ここでは (LSIDServiceConfig を使ってアクセスできる) 設定オプションを保存する必要がありませんので、何も行っていません。その次に来るのがgetKnownURIs の実装です。LSID オブジェクトの配列を返すわけですが、サポートしているLSIDは1個だけですので、要素が1個だけの配列を返しています。LSID のコンストラクターでは、MalformedLSIDException が発生する可能性があります。行27 - 31 は、LSIDサーバーのコードでの例外の一般的な処理方法を示しています。例外がLSIDServerException でない場合には、それをLSIDServerException でラップしてスローし直すようにします。このようにするのは、JavaのLSIDサーバー・スタックがLSIDServerException をSOAPのフォールト・メッセージに正しく変換できるようになっているからです。この過程で、スタックのトレース情報が失われることはありません。

関数getMetaDataLocations (行34 - 36) は、パラメーターにLSIDのオブジェクトをとり、そのLSIDについてのメタデータ・サービスが提供される場所の配列を返します。この例ではメタデータ・サービスを実装していませんので、このメソッドは長さ0の配列を返します (null を返すとエラーを示すことになります)。

関数getDataLocationsgetMetaDataLocations と非常によく似ていますが、こちらの関数はデータにもたせることのできる2つの場所 (仮想URLのhttp://www.ibm.com:80/lsid/hello_world.txtとftp://ftp.ibm.com/lsid/hello_world.txt) を示す配列を返します。

認定システムの実行とテスト

認定システムをテストするには、まずそれを配備する必要があります。それには、helloworld.warファイルをJakarta Tomcatのwebappsディレクトリーにコピーします。このファイルはTomcatの起動時にwebapps/helloworldに展開され、Hello World認定システムがhttp://localhost:8080/helloworld/ で利用できるようになります。

認定システムのサーブレットはwebapps/helloworld/WEB-INF/web.xmlというファイルに記述されています。


リスト2. Query認定システム
                
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems,
Inc.//Dtd Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp">
  <display-name>Hello World LSID Authority</display-name>
  <servlet>
    <servlet-name>AuthorityService</servlet-name>
    <display-name>Hello World Authority Servlet</display-name>
    <servlet-class>com.ibm.lsid.server.AuthorityServlet</servlet-class>
    <init-param>
      <param-name>service1</param-name>
      <param-value>*:* lsidsamples.HelloWorldAuthority</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>AuthorityService</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

この例では、必要なことすべてを標準のcom.ibm.lsid.server.AuthorityServlet が行ってくれますので、独自にJavaサーブレットを記述する必要はありませんでした。この認定システム・サーブレットはservice1service2 といった名前のパラメーターを使ってサービスを設定するようになっています。それぞれのサービスは認定システム/名前空間の特定の対〔つい〕を処理する責任があります。アスタリスク文字はワイルドカードの意味になります。サービスの順番にしたがってマッチングが行われます (サービス1、サービス2といった順番)。認定システム・サービスは、すべてcom.ibm.lsid.server.LSIDAuthorityService というインターフェースを実装していなければなりません。今回のサンプル認定システムlsidsamples.HelloWorldAuthority は、com.ibm.lsid.server.impl.SimpleAuthority を拡張することで、このインターフェースを実装しています。AuthorityServlet は、ロードされると、まずHelloWorldAuthority のインスタンスを作成し、次にgetMetaDataLocations 呼び出しおよびgetDataLocations 呼び出しを行って、LSID認定システムの標準メソッドgetAvailableOperations でのWSDL応答の作成に必要な情報を入手します。

認定システムのテストにはTestClient.javaというサンプル・クライアント・プログラムを使用します。そのコンパイル済みのクラス・ファイルは、展開されたsamplesディレクトリーにあるtest-client.jarファイルに入っています。以下のコマンドを入力します。

java TestClient urn:lsid:ibm.com:hello:world \
   http://localhost:8080/helloworld/

samples/test-client.jarとともに、クラス・パスに置かれたTomcatのshared/libディレクトリーの .jarファイルも使用します。TestClient に対する最初のパラメーターは、テストされるLSIDであり、2番目のパラメーターはibm.comの認定システム・サービスを一時的にHello World認定システムの稼働しているhttp://localhost:8080/helloworld/ にマップします。出力は以下のようなものになるはずです。

Authority version is: 3
The authority knows about 1 LSIDs:
  urn:lsid:ibm.com:hello:world
Data is available at:
(ftp)  ftp://ftp.ibm.com/lsid/hello_world.txt
(http) http://www.ibm.com:80/lsid/hello_world.txt


Swiss-Protデータ・セットの使い方

Swiss-ProtのレコードにはIDとACフィールドが含まれています。これは、そのレコードの識別番号と登録番号 (accession number) に対応しています。識別番号は人の目でも判読が可能です。われわれがこれから実装するSwiss-Prot認定システム・サンプルでは、以下のようないろいろな形式のLSIDを認識できるようにします。

表1. サポートされるLSID

サンプルLSID 説明
urn:lsid:example.org:swiss-id:hv20_mouse HV20_MOUSE というIDのSwiss-Protレコードを表す抽象的なLSIDで、データは何も含まれていません。このSwiss-Protレコードをいろいろなフォーマットで具体的に表現したものに、このLSIDが関係付けられます。
urn:lsid:example.org:swiss-id:hv20_mouse-sprot HV20_MOUSE というIDのSwiss-ProtフォーマットのSwiss-Protレコードのデータに名前を付ける具体的なLSID。
urn:lsid:example.org:swiss-id:hv20_mouse-fasta HV20_MOUSE というIDのFASTAフォーマットのSwiss-Protレコードのデータに名前を付ける具体的なLSID。FASTAへの変換は、今回はその場しのぎで行っており、読者の演習課題として残してあります。
urn:lsid:example.org:swiss-ac:p01879 第1登録番号または第2登録番号がP01879 のSwiss-Protレコードを表す抽象的なLSIDで、データは何も含まれていません。このSwiss-Protレコードをいろいろなフォーマットで具体的に表現したものに、このLSIDが関係付けられます。
urn:lsid:example.org:swiss-ac:p01879-sprot 登録番号がP01879 のSwiss-ProtフォーマットのSwiss-Protレコードのデータに名前を付ける具体的なLSID。
urn:lsid:example.org:swiss-ac:p01879-fasta 登録番号がP01879 のFASTAフォーマットのSwiss-Protレコードのデータに名前を付ける具体的なLSID。FASTAへの変換は、今回はその場しのぎの方法で行っています。

データ・セットの取得

Swiss-Protデータベースは、圧縮ファイルとしてexpasy.orgからftpでダウンロードすることができます (リンクは参考文献参照)。約63 Mバイトのデータ転送になります。sprot40.dat.gzというファイルを適当な場所 (~/lsid) に保存します。そして、以下のようにgunzipプログラムでこのファイルを展開します。

cd ~/lsid
gunzip -d sprot40.dat.gz

これが終わるとlsidディレクトリーにsprot40.datというファイルが作成されているはずです。このデータベースのファイル・フォーマットは、Swiss-Protのユーザー・マニュアルに説明があります (これについても、リンクは参考文献参照)。


MySQLデータベースへのデータのインポート

まず最初に行うべきことは、LSID認定システムで使用されるMySQLのユーザー・アカウントを作成し、必要なデータ・テーブルを作成することです。MySQLデーモンを実行していない場合には、★それを始動し (Red Hat Linux 7および8ではルートとしてetc/init.d/mysqldを始動)、mysql -u root -p とタイプして、ルート・ユーザーとしてMySQLクライアントを始動します。MySQLのルート・ユーザーのパスワードを指定し、以下の入力を行います。


リスト3. ユーザー・アカウントの作成
                
create database sprot4;
grant all on sprot4.*
  to lsiduser@localhost identified by 'none';
grant all on sprot4.*
  to lsiduser@localhost.localdomain identified by 'none';
grant all on sprot4.*
  to lsiduser@'%' identified by 'none';
use sprot4;
create table byid (
  id varchar(40) unique,
  version varchar(40),
  rootac varchar(40) unique,
  index(version)
);
create table byac (
  ac varchar(40) unique,
  rootac varchar(40),
  index(rootac)
);
create table acdata (
  rootac varchar(40) unique,
  data blob
);

キー入力を少なくしたい場合には、samplesディレクトリーからmysql.batch1というファイルをもってきて、mysql -f -u root -p < mysql.batch1 というコマンドを実行すればよいでしょう。これで、データベースsprot4へのアクセスが可能なユーザー・アカウントlsiduserがパスワードnoneで作成されます。次にbyid、byac、およびbyacdataの3つのテーブルを作成します。各テーブルの仕様は以下のとおりです。

表2. テーブルbyid

フィールド (列の名前) 意味
id名前空間swiss-id のLSIDを表す固有ID。長さは40文字まで。たとえばurn:lsid:example.com:SWISS-ID:HV20_MOUSE というLSIDの場合、idHV20_MOUSE という文字列が指定されます。
versionオプションの (NULLにすることもできる) 最大40文字までのバージョン文字列。urn:lsid:example.com:SWISS-ID:HV20_MOUSE:version2 というLSIDの場合、このフィールドにはversion2 が指定されます。今回の例では、このフィールドは使用しません。
rootac対応するLSIDのSwiss-Protの第1登録番号。urn:lsid:example.com:SWISS-ID:HV20_MOUSE というLSIDの場合、このフィールドにはP01789 という値が指定されます。このLSIDのデータをアクセスする際に、この第1フィールドが使用されます。

表3. テーブルbyac

フィールド (列の名前) 意味
acSwiss-Protの登録番号 (最大40文字)。第2登録番号 (P01234 など) をこのフィールドに指定することができます。この番号はswiss-ac という名前空間内のオブジェクトIDに対応します。
rootac対応する登録番号のSwiss-Protの第1登録番号。urn:lsid:example.com:SWISS-AC:P01234 というLSIDの場合、このフィールドにはP08751 という値が指定されます。このLSIDのデータをアクセスする際に、この第1フィールドが使用されます。

表4. テーブルacdata

フィールド (列の名前) 意味
rootacSwiss-Protレコードを識別するためのSwiss-Protの第1登録番号。
dataSwiss-Protフォーマットのrootacに対応するSwiss-Protレコードを入れたバイナリー・データ・オブジェクト。これが当該LSIDについて返されてくる実際のデータです。

MySQLへのデータのロード

新たに作成したテーブルにデータをインポートするには、まずフラット・ファイルsprot40.datからデータを抽出する必要があります。これには、先にそのためにダウンロードしておいたsamplesディレクトリーに含まれているPerlスクリプトextract.plを使用します。以下のようにして実行します。

cd ~/lsidperl extract.pl sprot40.dat byid.txt byac.txt acdata.txt

データ・セットがかなり大きいため、これにはある程度時間がかかります。またインポート処理の際は、データを溜めておくための充分なディスク・スペースが必要です。extract.plの処理が完了したら、MySQLのクライアントをユーザーlsiduserとして始動することができます。それにはmysql -u lsiduser -pnone とタイプし、以下のコマンドを入力します。

use sprot4;     
load data local
  infile 'byid.txt' into table byid;
load data local
  infile 'byac.txt' into table byac;
load data local
  infile 'acdata.txt' into table acdata;;
  

この処理にも、ある程度の時間がかかります。これが終わったら、byid.txt、byac.txt、acdata.txtの3つのファイルは削除してかまいません。キー入力を少なくしたい場合には、samplesディレクトリーからmysql.batch2をもってきてmysql -f -u lsiduser -pnone < mysql.batch2 を実行すればよいでしょう。

Javaコード

今度は、もう少し実際的なLSID認定システムを見てみたいと思います。このシステムでは、LSIDを解決するための認定システム・サービス、Swiss-ProtとFASTAの両方のフォーマットのデータ・レコードを扱うデータ・サービス、およびある一定のメタデータだけをサポートするメタデータ・サービスを用意します。認定システム・コードの核心部分に入っていく前に、samplesアーカイブに入っているSampleLSIDDataLookup.javaのサポート・ルーチンをざっと眺めておきたいと思います。


リスト4. Javaによるデータ検索
                
package com.ibm.lsid.samples;
import java.io.InputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.ibm.lsid.LSID;
import com.ibm.lsid.MalformedLSIDException;
import com.ibm.lsid.server.LSIDServerException;
public class SampleLSIDDataLookup {
  ...
  public SampleLSIDDataLookup() throws LSIDServerException {
    ...
  }
  public int lsidType(LSID lsid) throws LSIDServerException {
    ...
  }
  public InputStream lsidData(LSID lsid) throws LSIDServerException {
    ...
  }
}

lsidType およびlsidData の実装は、さして重要ではありません。これらの関数が行うことは、基本的にLSIDのタイプ (UNKNOWN、ABStrACT、またはCONCRETE) およびそのタイプにInputStream オブジェクトとして結合されているデータを返すことです。エラーが検出された場合には、適当なLSIDServerException 例外がスローされます。

認定システムの核心部分の機能はSampleLSIDAuthorityMain クラスで実装されています (リスト5)。


リスト5. SampleLSIDAuthorityMainクラス
                
package com.ibm.lsid.samples;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import com.ibm.lsid.LSID;
import com.ibm.lsid.LSIDException;
import com.ibm.lsid.ExpiringResponse;
import com.ibm.lsid.wsdl.LSIDDataPort;
import com.ibm.lsid.wsdl.LSIDMetaDataPort;
import com.ibm.lsid.wsdl.LSIDWSDLWrapper;
import com.ibm.lsid.server.LSIDServerException;
import com.ibm.lsid.server.LSIDServiceConfig;
import com.ibm.lsid.server.impl.HTTPDataLocation;
import com.ibm.lsid.server.impl.HTTPMetaDataLocation;
import com.ibm.lsid.server.impl.SOAPDataLocation;
import com.ibm.lsid.server.impl.SOAPMetaDataLocation;
import com.ibm.lsid.server.impl.SimpleAuthority;
public class SampleLSIDAuthorityMain extends SimpleAuthority {
  private SampleLSIDDataLookup lookup = null;
  public void initAuthority(LSIDServiceConfig cf) throws LSIDServerException {
    lookup = new SampleLSIDDataLookup();
  }
  public ExpiringResponse getKnownURIs() throws LSIDServerException {
    return null;
  }
  public LSIDMetaDataPort[] getMetaDataLocations(LSID lsid, String url) {
    if (lookup == null)
      return null;
    int lsType;
    try {
      lsType = lookup.lsidType(lsid);
    }
    catch (LSIDServerException ex) {
      ex.printStackTrace();
      lsType = SampleLSIDDataLookup.UNKNOWN;
    }
    if (lsType == SampleLSIDDataLookup.UNKNOWN)
      return null;
    HostDescriptor hd = new HostDescriptor(url);
    return new LSIDMetaDataPort[] {
      new SOAPMetaDataLocation(
        hd.baseURL + "metadata"
      )
    };
  }
  public LSIDDataPort[] getDataLocations(LSID lsid, String url) {
    if (lookup == null)
      return null;
    int lsType;
    try {
      lsType = lookup.lsidType(lsid);
    }
    catch (LSIDServerException ex) {
      ex.printStackTrace();
      lsType = SampleLSIDDataLookup.UNKNOWN;
    }
    if (lsType == SampleLSIDDataLookup.UNKNOWN)
      return null;
    if (lsType == SampleLSIDDataLookup.ABStrACT)
      return new LSIDDataPort[0];
    HostDescriptor hd = new HostDescriptor(url);
    return new LSIDDataPort[] {
      new SOAPDataLocation(
        hd.baseURL + "data"
      ),
      new HTTPDataLocation(
        hd.host, hd.port,
        hd.pathPrefix + "/authority/data?" + lsid
      )
    };
  }
  private static final Pattern HOST_PTN = Pattern.compile(
    "https?://([^/:]+)(?::(\\d+))?(.*)/authority(.*)"
  );
  /* Q&D implementation */
  private class HostDescriptor {
    public String host;
    public int port;
    public String pathPrefix;
    public String baseURL;
    public HostDescriptor(String url) {
      host = "localhost";
      port = -1;
      pathPrefix = "";
      if (url != null || url.length() > 0) {
        Matcher m = HOST_PTN.matcher(url);
        if (m.lookingAt()) {
          host = m.group(1);
          if (m.group(2).length() > 0)
            port = Integer.parseInt(m.group(2));
          pathPrefix = m.group(3);
        }
      }
      if (port > 0)
        baseURL = "http://" + host + ":" + port +
          pathPrefix + "/authority/";
      else
        baseURL = "http://" + host + pathPrefix + "/authority/";
    }
  }
}

initAuthority 関数で行っているのは、解決を依頼されたLSIDの存在を確認するために使用するSampleLSIDDataLookup オブジェクトを用意することだけです。関数getKnownURIs は、このサービスで把握されているすべてのLSIDのリストではなくnull を返します。そうしないと、このサービスで参照可能な約480,000個のLSIDを表す何メガ・バイトにも及ぶ応答になってしまいます。

重要なメソッドの1つ目はgetMetaDataLocations です。このメソッドは、getAvailableOperations サービス・メソッドを要求するSOAPリクエストが処理されるときに、認定システム・サーブレットから呼び出されます。指定されたLSIDの存在が確認できると、場所 (今回のメタデータ・サービスのエンドポイント) を1個入れた配列を返します。以下の行については少し詳しく説明する必要があります。

new SOAPMetaDataLocation(
  hd.baseURL + "metadata"
)

SOAPMetaDataLocation クラスは、SOAPのエンドポイント専用のLSIDMetaDataPort インターフェースを具体的に実装したものです。このコンストラクターに対する引数は、外部に公開されるメタデータ・サービスの完全修飾URLであり、ここではプライベート・クラスHostDescriptor のメソッドを使って、このURLを作成しています。

getDataLocations メソッドも格好は非常によく似ていますが、こちらはメタデータの場所を指定するのではなく、LSIDに結合されているデータを入手できる場所を指定します。SOAPDataLocationHTTPDataLocation は両方ともLSIDDataPort インターフェースを具体的に実装したものです。SOAPDataLocation は引数に完全修飾URLをとるだけですが、HTTPDataLocation はホスト名、データ・ポート、およびデータへのパスを引数とします。

LSID解決サーバーで次にくるのはデータ・サービスです。ここでは、LSIDDataService インターフェースを実装し、それをLSIDパッケージに用意されているDataServlet サーブレット・クラスにパラメーターとして渡しています。


リスト6. データ・サービス
                
package com.ibm.lsid.samples;
import java.io.InputStream;
import com.ibm.lsid.LSID;
import com.ibm.lsid.server.LSIDDataService;
import com.ibm.lsid.server.LSIDServerException;
import com.ibm.lsid.server.LSIDServiceConfig;
public class SampleLSIDAuthorityData implements LSIDDataService {
  private SampleLSIDDataLookup lookup = null;
  public InputStream getData(LSID lsid) throws LSIDServerException {
    if (lookup == null)
      throw new LSIDServerException(500, "Cannot query database");
    return lookup.lsidData(lsid);
  }
  public void initDataService(LSIDServiceConfig cf) throws LSIDServerException {
    lookup = new SampleLSIDDataLookup();
  }
}

データ・サービスの実装は、サポート・クラスのSampleLSIDDataLookup が力仕事をやってくれていますので、大したことを行っていません。なおFASTAフォーマットのデータは、samplesパッケージに収められているSwissToFastaConverter という小さなユーティリティー・クラスを使ってSwiss-Protレコードからその場しのぎの方法で作成されていることを付記しておきます。

パッケージを完成させるにはgetMetaDatainitMetaDataService の実装を用意する必要があります。初期化では何も特別なことは行っていませんし、getMetaData は認識されたLSIDについての適当なRDF記述を作成しているだけです。


リスト7. メタデータの取得
                
package com.ibm.lsid.samples;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import com.ibm.lsid.LSID;
import com.ibm.lsid.ExpiringResponse;
import com.ibm.lsid.MalformedLSIDException;
import com.ibm.lsid.server.LSIDMetaDataService;
import com.ibm.lsid.server.LSIDServerException;
import com.ibm.lsid.server.LSIDServiceConfig;
public class SampleLSIDAuthorityMetaData implements LSIDMetaDataService {
  private SampleLSIDDataLookup lookup = null;
  public void initMetaDataService(LSIDServiceConfig cf) throws LSIDServerException {
    lookup = new SampleLSIDDataLookup();
  }
  private static final String RDF_NS=
    "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
  private static final String DC_NS=
    "http://purl.org/dc/elements/1.1/";
  private static final String I3CP_NS=
    "urn:lsid:i3c.org:predicates:";
  private static final String I3C_CONTENT=
    "urn:lsid:i3c.org:types:content";
  private static final String I3C_SPROT=
    "urn:lsid:i3c.org:formats:sprot";
  private static final String I3C_FASTA=
    "urn:lsid:i3c.org:formats:fasta";
  private void appendTripleResource(
    StringBuffer src,
    String subj, String pred, String obj
  ) {
    src.append("<rdf:Description rdf:about=\"");
    src.append(subj);
    src.append("<");
    src.append(pred);
    src.append(" rdf:resource=\")");
    src.append(obj);
    src.append("\"/></rdf:Description>");
  }
  public ExpiringResponse getMetaData(LSID lsid) throws LSIDServerException {
    int lsType;
    try {
      lsType = lookup.lsidType(lsid);
    }
    catch (LSIDServerException ex) {
      ex.printStackTrace();
      lsType = SampleLSIDDataLookup.UNKNOWN;
    }
    if (lsType == SampleLSIDDataLookup.UNKNOWN)
      throw new LSIDServerException(201, "Unknown LSID");
    StringBuffer result= new StringBuffer();
    result.append("<?xml version=\"1.0\"?><rdf:RDF");
    result.append(" xmlns:rdf=\"");
    result.append(RDF_NS);
    result.append("\" xmlns:dc=\"");
    result.append(DC_NS);
    result.append("\" xmlns:i3cp=\"");
    result.append(I3CP_NS);
    result.append(">");
    String baseLSID= lsid.toString();
    if (baseLSID.endsWith("-fasta") || baseLSID.endsWith("-sprot"))
      baseLSID.substring(0, baseLSID.length() - 6);
    if (lsType == SampleLSIDDataLookup.ABStrACT) {
      appendTripleResource(
        result,
        baseLSID, "i3cp:storedas", baseLSID + "-fasta"
      );
      appendTripleResource(
        result,
        baseLSID, "i3cp:storedas", baseLSID + "-sprot"
      );
      appendTripleResource(
        result,
        baseLSID + "-fasta", "rdf:type", I3C_CONTENT
      );
      appendTripleResource(
        result,
        baseLSID + "-sprot", "rdf:type", I3C_CONTENT
      );
      appendTripleResource(
        result,
        baseLSID + "-fasta", "dc:format", I3C_FASTA
      );
      appendTripleResource(
        result,
        baseLSID + "-sprot", "dc:format", I3C_SPROT
      );
    }
    else {
      String format= I3C_SPROT;
      if (lsid.getObject().endsWith("-fasta")) {
        format= I3C_FASTA;
      }
      appendTripleResource(
        result,
        baseLSID, "i3cp:storedas", baseLSID + "-fasta"
      );
      appendTripleResource(
        result,
        lsid.toString(), "rdf:type", I3C_CONTENT
      );
      appendTripleResource(
        result,
        lsid.toString(), "dc:format", format
      );
    }
    result.append("</rdf:RDF>");
    return new ExpiringResponse(
      new ByteArrayInputStream(
        result.toString().getBytes()
      ),
      null
    );
  }
}

認定システムの実行とテスト

Swiss-Protの認定システムをテストするには、まずswiss-prot.warというファイルをJakarta Tomcatのwebappsディレクトリーにコピーしておきます。Tomcatの起動時に、このファイルがwebapps/swiss-protに展開され、認定システム・サービスがhttp://localhost:8080/swiss-prot/authority/ で利用できるようになります。この認定システムもHello WorldのLSID認定システムと同様TestClient を実行することでテストできます。

java TestClient urn:lsid:ibm.com:swiss-id:hv20_mouse \
http://localhost:8080/swiss-prot/authority/

以下のような出力になるはずです。

Authority version is: 3
The authority knows about 0 LSIDs:
Meta is available at:
(soap) http://localhost:8080/swiss-prot/authority/metadata
-- META DATA --
<?xml version="1.0"?><rdf:RDF xmlns:rdf="http://www.w3.org/199....
----

データを結合したLSIDでテストしたい場合には、次のコマンドで試してみるとよいでしょう。

Java TestClient urn:lsid:ibm.com:swiss-id:hv20_mouse-fasta \
http://localhost:8080/swiss-prot/authority/

この場合、以下のような出力になるはずです。

Authority version is: 3
The authority knows about 0 LSIDs:
Data is available at:
(soap) http://localhost:8080/swiss-prot/authority/data
(http) http://localhost:8080/swiss-prot/authority/data?
urn:lsid:ibm.com:swiss-id:hv20_mouse-fasta
Meta is available at:
(soap) http://localhost:8080/swiss-prot/authority/metadata
-- DATA --
>HV20_MOUSE (P01789) Ig heavy chain V region M603.
EVKLVESGGGLVQPGGSLRLSCATSGFTFSDFYMEWVRQPPGKRLEWIAASRNKGNKYTTEYSASVKGRFIVSRDTSQ
SILYLQMNALRAEDTAIYYCARNYYGSTWYFDVWGAGTTVTVSS
----
-- META DATA --
<?xml version="1.0"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/......
----


メタデータ

LSIDのメタデータはRDFを使って記述できます (これについては参考文献に掲げたRDF Primerを参照してください)。LSIDについての有効な最小限の情報は、そのLSIDにデータが結合されているかどうか、それがどんなフォーマットのデータなのか、あるいはLSIDにデータが結合されていない場合、何らかのフォーマットによる概念の具体的な表現がどこで取得できるのか、といったことです。

RDFについて

RDF文書 は、主語、述語および目的語 (値) の3つの部品からなる簡単な文を並べることで構成されます。「Spot barks like a dog」はRDFの三つ組 (triple) を英語で表したもので、Spotが主語、barks likeが述語、dogが目的語です。RDFは、要するに、そうした情報を形式的に符号化しようというものです。何かのLSIDについてのメタデータはRDFの文のコレクションとして構成されます。述語 (プロパティーとも言える) 自体は、何らかの種類の主語 (資源) であると考えることができます。RDF Schema Specification (参考文献参照) は、RDFの文を使って述語同士の関係を記述する方法を規定しています。主語と述語は必ずURIによって命名され、LSIDはURIの一種であるURNですので、LSIDはRDF文または述語として使用することができます。RDFの目的語は、URI (この場合LSIDが使用できる) ★または型指定されることもあればされないこともある、いわゆる「リテラル」値のいずれかです。

urn:lsid:pets.org:cats:Tom というLSIDが猫の名前を表しているものとします。この場合のLSIDは、Tomという猫の抽象的な概念を表現しており、Tomを表す特定的で不変のビットのコレクションを表現しているわけではありません。しかしTomに関係するものには、Tomが子猫であることを示す写真など、具体的なデジタル表現を伴うものがいろいろと存在します。たとえばurn:lsid:pets.org:cats:Tom-photos:Nov-22-1998 がTomを写している何かの写真を表すものだとします。この場合、RDFのプロパティーurn:lsid:i3c.org:predicates:storedAs を使い、以下のようにしてこの写真をurn:lsid:pets.org:cats:Tom に「結合」することができます。

<rdf:Description rdf:about="urn:lsid:pets.org:cats:tom">
    <i3c:storedas rdf:resource="urn:lsid:pets.org:cats:tom-photos:nov-22-1998"/>
</rdf:Description>

なおLSIDでは大文字・小文字が区別されませんが、RDFのURIは大文字・小文字が区別されます。エラーの原因とならないように、RDF中のLSIDは必ずその正規形式である小文字で表現するようにしたほうがよいでしょう。XMLタグのi3c:storedas は変な感じがしますが、プロパティーの名前です。名前空間プレフィックスi3curn:lsid:i3c.org:predicates: を表しているものとすると、完全修飾のプロパティー名はurn:lsid:i3c.org:predicates:storedas (プレフィックスとタグ名を連結したもの) になります。

Tomの写真にはデータが結合されていますので、メタデータにそのことを記述する必要があります。クラスurn:lsid:i3c.org:types:content はデータの結合されているものをすべて網羅していますので、Tomの写真は、このクラスに属しています。このことはRDF文で以下のように記述します。

<rdf:Description rdf:about="urn:lsid:pets.org:cats:tom-photos:nov-22-1998">
    <rdf:type rdf:resource="urn:lsid:i3c.org:types:content"/>
</rdf:Description>

rdf:type プロパティーは、クラスのメンバーシップを示すために使用されます。名前空間プレフィックスrdf は、通例、RDFの仕様で定義されている名前空間http://www.w3.org/1999/02/22-rdf-syntax-ns# を表現するために使用されます。

最後に、Tomの写真はJPEGなど何かのフォーマットで保存されます。このことを示すために、Dublin Core RDFの語彙 (参考文献参照) の一部を利用することができます。LSIDのurn:lsid:i3c.org:formats:jpg はJPEGデータ・フォーマットという概念を表します。以下のRDF文で、このことがすべて記述されます。

<rdf:Description rdf:about="urn:lsid:pets.org:cats:tom-photos:nov-22-1998">
    <dc:format rdf:resource="urn:lsid:i3c.org:formats:jpg"/>
</rdf:Description>

dc:format プロパティーは資源のフォーマットを記述するために使用されます。名前空間プレフィックスdc は、通例、名前空間http://purl.org/dc/elements/1.1/ を表すために使用されます。

RDF文書は、よく相互連関グラフとして表示されます。われわれの例は以下のような図式になります。


図1. グラフによる関係の表現
図1. グラフによる関係の表現

メタデータの永続性について

LSIDに結合されるデータと違い、メタデータは期限切れになることがあります。このことは、LSIDのメタデータが当該オブジェクトに関する一時的な情報を保存しておくのに最適な場所であるということを意味します。たとえば、Tomという猫のホームページへのリンクがTomのメタデータに含まれることもあるでしょうが、リンクはいつでも変更することができます。

メタデータへの値の追加

可能なかぎり、資源のコレクションの記述には標準のプロパティー名を使用すべきです。標準的な語彙を使用することで、メタデータの供給側と消費側の間の相互運用性の可能性は大いに高くなります。他方、指定された関係を既存のプロパティーでは適切に記述できない場合があることも事実です。そういう場合には、目的に応じて新しいプロパティーを考え出せばよいでしょう。プロパティーがRDF SchemaやWeb Ontology Languageで記述されていれば、RDF Schema対応のクライアントは、皆さんの使用する述語についての明確な知識がない場合でも、そのメタデータの意味を理解することができます。

LSIDを場所独立なものとしLSIDの不変性を保証するなら、LSIDはデータベースのクロス参照に最適な候補となります。2つのLSIDの間の重要な関係がわかっているのであれば、それらのLSIDを誰が発行したのかに関らず、その関係をメタデータに記述すべきです。LSIDを解決できるクライアントなら、LSIDの出所〔でどころ〕に関係なく、そういったことを行えるはずです。


認定システムを一般に公開する

LSID Resolution Proposal (LSID解決仕様案) に準拠させ、認定システムを一般に公開するためには、クライアントがサービスの正確な所在を予め知っていなくてもその認定システムで処理されるLSIDを解決できるようにする必要があります。つまり認定システムのクライアントが自分のところのauthorities を編集したり、同様の作業を行わなくてもよいようにしなくてはなりません。

これを解決するための第1歩は、認定システムにDNSサービス・レコードを設けることです。pdb.orgの認定システムを例にとると、そのLSIDサービスが配置されているホストの名前とポート番号を知る必要があります。それには、以下のコマンドを入力します。

host -t srv _lsid._tcp.pdb.org

ネットワーク・プロトコルにTCPを使っているpdb.orgのlsidサービス・レコードをDNSに尋ねているわけです。以下のような応答が得られるはずです。

_lsid._tcp.pdb.org SRV 1 0 8080 lsidauthority.pdb.org.

これによって、pdb.orgの認定システム・サービスがlsidauthority.pdb.orgという名前のホストで実行されていてTCPポート8080で接続を待機していることがわかります。残念ながら、この情報はpdb.orgの認定システム・サービスのエンドポイントを決定するには不充分です。サービスはホストのパス /authority/ に用意しなければならないとLSID Resolution Proposalが規定しているのはこのためです。したがってpdb.orgの認定システム・サービスの完全修飾URLはhttp://lsidauthority.pdb.org:8080/authority/ であることになります。

DNSの設定

皆さん (または皆さんのシステム管理者) が行うべきことは、認定システムを実行するマシンのサービス・レコードを追加することです。たとえば、マシンがauthority.company.netで、そのマシンによってcompany.netという名前の認定システムがサービスされるものとします。また、そのサービスがポート8080に配置されるものとします。この場合、レコードはcompany.netのDNSサーバーのマスター・ゾーン・ファイル (おそらくcompany.net上の /var/named/company.net.zoneという名前のファイル) に追加する必要があります。

_lsid._tcp      IN      SRV     1       0       8080    authority.company.net.

認定システムの名前がcompany.netではなくauthority.company.netであれば、company.netのゾーン・ファイルのレコードは以下のようなものになります。

_lsid._tcp.authority    IN      SRV     1       0       8080    authority.company.net.


まとめ

本稿の順を追って解説していくという方法および参考文献に示したzipファイルで提供されるsamplesディレクトリーの広範な内容によって、皆さんが簡単にシステムを立ち上げられることになれば幸いです。時間や手間を節約したいという同じ精神から、DNS管理者にSRVレコードの実装を要求する際の電子メールの文面として利用できるメモも以下に掲げておくことにします。

To: <ここにDNS管理者の名前を入れる>
cc: <ここに所属長の名前を入れる>
Subject: 私のLSID Authorityを解決するためのDNSレコード 適当なゾーン・ファイルに以下のSRVレコードを追加していただけません
でしょうか。 _lsid._tcp IN SRV 1 0 <ここにポート番号を入れる> <ここにAuthorityのホスト名を入れる>. BIND v4以上または同等のDomain Name Serviceを実行している場合には、
そのシステムはSRVレコードをサポートするはずです (RFC 2782)。 このSRVレコードを設けるのは、LSIDプロトコル
(http://www.i3c.org/workgroups/techarch/resources/lsid/docs/LSIDSyntax9-20-02.htmを
参照してください) を実行しているクライアントが、
<ここにAuthorityのホスト名を入れる> のポート <ここにポート番号を入れる
> で私が実行しているLSID Authorityサーバーに解決できるようにするためです。 LSIDプロトコル、解決モデル、および
Authorityサーバーの詳細については、http://ibm.com/developerworks/oss/lsidを参照してください。 なお、これがいつから有効になるのかお知らせいただければ幸いです。 よろしくお願いいたします。 敬具

参考文献

著者について

Stefan Atev氏は、Extreme Blue 2001インターンシップ・プログラムの卒業生です。SashXB Webサービスのクライアントの研究を続けてきた後、現在はLife Sciences Identifierプロジェクトに参加し、Life Sciencesデータ・ストアを実装したり、セマンティックWebテクノロジーを応用して既存のLife Sciencesデータベースの使いやすさの改善を図ったりしています。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Linux, Java technology, SOA and Web services
ArticleID=237201
ArticleTitle=Linux上にLSID認定システムを構築する
publish-date=05272003
author1-email=
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。