近年では、途方もなく大量の生物学的データが作成されています。生物学者や生物情報科学者なら、仕事に役立つ非常に便利な資源がネットワークのあちこちで提供されているのをご存じだろうと思いますが、こうした情報にアクセスするにはいろいろな約束ごとを覚えなければならず、生産性を消耗させることがよくあります。多分皆さんは、そのための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 LSIDクライアント/サーバー・スタックを利用するには、まず以下のパッケージをインストールしておく必要があります。
-
Xalan-J 2.4.1
- xalan.jar
- xml-apis.jar
- xercesImpl.jar
-
JAR with javax.xml.namespace.QName API Class Files 1.0
- jax-qname.jar
-
WSDL for Java
- wsdl4j.jar
-
Jena2 RDFツールキット (必ずしも必要ではない)
- jena.jar
- icu4j.jar
- concurrent-1.3.0.jar
- log4j-1.2.7.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 Javaクライアント/サーバー・スタックの最新バージョン (本稿執筆時点でのバージョンは0.3) を入手します。 バイナリーのLSIDサーバー・ディストリビューション バイナリーのLSIDクライアント・ディストリビューション を入手し、lsid-client.jarファイルおよびlsid-server.jarファイルをJakarta Tomcatのshared/libディレクトリーにコピーします。
Java LSIDサーバー・パッケージには、完全機能版のLSID解決サービスの他に、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 }
|
行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 を返すとエラーを示すことになります)。
関数getDataLocations はgetMetaDataLocations と非常によく似ていますが、こちらの関数はデータにもたせることのできる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サーブレットを記述する必要はありませんでした。この認定システム・サーブレットはservice1、service2 といった名前のパラメーターを使ってサービスを設定するようになっています。それぞれのサービスは認定システム/名前空間の特定の対〔つい〕を処理する責任があります。アスタリスク文字はワイルドカードの意味になります。サービスの順番にしたがってマッチングが行われます (サービス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のレコードには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のユーザー・マニュアルに説明があります (これについても、リンクは参考文献参照)。
まず最初に行うべきことは、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の場合、id にHV20_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
| フィールド (列の名前) | 意味 |
| ac | Swiss-Protの登録番号 (最大40文字)。第2登録番号 (P01234 など) をこのフィールドに指定することができます。この番号はswiss-ac という名前空間内のオブジェクトIDに対応します。 |
| rootac | 対応する登録番号のSwiss-Protの第1登録番号。urn:lsid:example.com:SWISS-AC:P01234 というLSIDの場合、このフィールドにはP08751 という値が指定されます。このLSIDのデータをアクセスする際に、この第1フィールドが使用されます。 |
表4. テーブルacdata
| フィールド (列の名前) | 意味 |
| rootac | Swiss-Protレコードを識別するためのSwiss-Protの第1登録番号。 |
| data | Swiss-Protフォーマットのrootacに対応するSwiss-Protレコードを入れたバイナリー・データ・オブジェクト。これが当該LSIDについて返されてくる実際のデータです。 |
新たに作成したテーブルにデータをインポートするには、まずフラット・ファイル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 を実行すればよいでしょう。
今度は、もう少し実際的な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に結合されているデータを入手できる場所を指定します。SOAPDataLocation とHTTPDataLocation は両方とも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レコードからその場しのぎの方法で作成されていることを付記しておきます。
パッケージを完成させるにはgetMetaData とinitMetaDataService の実装を用意する必要があります。初期化では何も特別なことは行っていませんし、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文書 は、主語、述語および目的語 (値) の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 は変な感じがしますが、プロパティーの名前です。名前空間プレフィックスi3c がurn: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. グラフによる関係の表現
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/ であることになります。
皆さん (または皆さんのシステム管理者) が行うべきことは、認定システムを実行するマシンのサービス・レコードを追加することです。たとえば、マシンが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を参照してください。 なお、これがいつから有効になるのかお知らせいただければ幸いです。 よろしくお願いいたします。 敬具
- 本稿で使用したコード・サンプルやバッチ・ファイルは、すべて1個のzipアーカイブjava-samples.tar.gz に収められています (ファイルは、すべてアーカイブを展開して得られるsamplesサブディレクトリーに保存されます)。
- 本稿のサンプルを実行するために必要なJavaパッケージはダウンロードすることができます。
-
LSID Resolution Protocol Project は、LSIDの
クライアント
サーバー
・スタック、並びにLSID LaunchPad というサンプル・クライアントを提供しています。
-
Swiss-Prot データベースは、圧縮ファイルとしてftp経由でダウンロードできます。
- テスト用にSwiss-Protのデータ・セットを使ってサンプルの認定システムをセットアップしたい場合には、MySQL ABで入手できるMySQL Connector/J ディストリビューションに含まれているmysql-connector-java-x.x.x-bin.jarというファイルも必要になります。
- データベースsprot40.datのファイル・フォーマットについては、Swiss-Protユーザー・マニュアルに説明があります。
- Perlのほうが使いやすいという方は、Stefanによる同様の記事の 「Setting up your own LSID Authority using Perl」を読まれるとよいでしょう。
- Life Sciences Identifier (LSID) は、現在策定中のI3CのUniform Resource Name (URN) の仕様です。この仕様については、I3Cのサイトに詳しい説明が示されています。
- RDFでLSIDのメタデータを記述する方法についてはRDF Primer が参考になります。
-
RDF Schema Specification は、RDFの文を使って述語同士の関係を記述する方法を規定しています。
- 本稿ではDublin Core RDFの語彙 の一部を使ってTomの写真にどんなファイル・フォーマットを使用しているのかを指定しています。
-
IBM WebSphereダウンロード・センター からダウンロード可能な製品や役に立つ参考文献、高度な情報、証明を入手することができます。
- IBMのalphaWorksからはNational Center for Biotechnology Information (NCBI) のWebサイトに照会を行うWeb Services for Life Sciences パッケージを無料でダウンロードすることができます。
-
IBM Life Sciences は、バイオテクノロジー、薬学、ゲノム解析、たんぱく質工学 (proteomics)、保健医療に関係するITのニーズに対応しています。
- IBMの研究者は、化学、コンピューター・サイエンス、電気工学、材料科学、数学、物理学など、数多くの科学・技術の学問分野に従事しています。関連する情報がIBM Research のサイトでも紹介されています。
- この他developerWorks には、オープン・ソース・プロジェクト、Linux、Javaテクノロジー、Webサービスに関する参考文献が多数掲載されています。