レベル: 中級 米持 幸寿, テクノロジー・エバンジェリスト, IBM
2006年 5月 10日
連載第5回の前回、書籍検索のインターフェースをデザインしてみる作業を紹介しました。
このようにして考え出されたインターフェースは、なんらかの方法で表現しなければなりません。
まずは表に
まずはとても古い方法からいきましょう。表にしてみる、という手です。日本人はとにかく表が好きです。たぶん、インターフェースの検討会議などを行うときも、プロジェクターに表を投影しながら議論することになります。ですから、表にすることはけっこう重要です。
表にするときも、インターフェースの作りをつねに意識します。それは、インターフェース型(portType)、操作(operation)メッセージ(message)という階層構造と、メッセージに使われるデータの型が必要である、ということです。
筆者は通常、次のような表でデータ構造とインターフェースを記述していきます。
表1.書籍情報
| データ型名 | メンバー | 型 | 説明 |
|---|
| BookInfo | title | 文字列 | 書籍のタイトル | | subtitle | 文字列 | サブタイトル | | author | 文字列 | 筆者名 | | publisher | 文字列 | 出版業者 | | isbn | 文字列 | ISBN番号 | | picture | 文字列 | 写真 | | price | 整数 | 価格 |
表2.書籍検索結果データ
| データ型名 | メンバー | 型 | 説明 |
|---|
| SearchBooksResultItem | linenumber | 整数 | 行番号 | | isbn | 文字列 | ISBN番号 | | title | 文字列 | タイトル | | author | 文字列 | 著者名 |
表3.書籍検索結果
| データ型名 | メンバー | 型 | 説明 |
|---|
| SearchBooksResult | resulttotal | 整数 | 検索した結果のヒット数 | | results | SeachBooksResultItem[ ] | 書籍検索結果データの配列 |
表4.顧客情報
| データ型名 | メンバー | 型 | 説明 |
|---|
| Customer | customerid | 文字列 | 顧客番号 | | name | 文字列 | 顧客名 | | address | 文字列 | 住所 | | age | 整数 | 年齢 | | tel | 整数 | 電話番号 |
表5.書籍注文明細行
| データ型名 | メンバー | 型 | 説明 |
|---|
| BookOrderItem | isbn | 文字列 | ISBN番号 | | quantity | 整数 | 冊数 | | subtotal | 整数 | 明細合計 |
表6.書籍注文データ
| データ型名 | メンバー | 型 | 説明 |
|---|
| BookOrder | items | BookOrderItem[ ] | 注文明細行の配列 | | customer | Customer | 顧客情報 | | ordernumber | 文字列 | 注文番号 | | primarytotal | 整数 | 小計 | | tax | 整数 | 消費税 | | total | 整数 | 合計 |
表7.書籍注文インターフェース
ポート型名:「
BookSearcher
」
| 操作名 |
| メッセージ名 | メッセージ内容 | 型 | 説明 |
|---|
| getCategories | 最初の一文字を指定して、カテゴリー一覧を取得する | | → | GetCategoriesRequest | initial | 文字列 | カテゴリー名の最初の一文字 | | ← | GetCateoriesResponse | categories | 文字列[ ] | カテゴリー名一覧 | | searchBooksByCategory | 特定のカテゴリーの書籍を検索し、検索結果を返す | | → |
SearchBooks
ByCategoryRequest
| category | 文字列 | カテゴリー名 | | start | 整数 | 結果開始位置 | | lines | 整数 | 結果行数 | | ← | SearchBooksResponse | result |
SearchBooks
Result
| 検索結果 | | getBookByISBN | ISBN番号を使って書籍情報を取り出す | | → | GetBookByISBNRequest | isbn | 文字列 | ISBN番号 | | ← | GetBookByISBNResponse | bookinfo | BookInfo | 書籍情報 |
表8.書店インターフェース
ポート型名「
BookStore
」
| 操作名 |
| メッセージ名 | メッセージ内容 | 型 | 説明 |
|---|
| order | 書籍を注文する | | → | OrderRequest | bookorder | BookOrder | 書籍注文データ | | ← | OrderResult | orderresult | OrderResult | 注文結果データ |
プログラミング・インターフェースで定義してみる
おいおい、抽象インターフェースじゃなかったのか?と抗議されそうですが、まずはプログラマの人に一番簡単なプログラミング・インターフェースからいきましょう。SOAの抽象インターフェースは、プログラミング言語でも定義することができます。
Javaで実装してみます。Javaでは以下のようなルールで作ります。
-
データは、Serializable インターフェースを実装したデータクラスとし、アクセサを定義する
-
ポート型の単位でインターフェース・クラス(interface)を定義し、メソッドからはRemoteException
がスローされることを宣言する。このインターフェース・クラスを「
エンドポイント・インターフェース
」と呼びます。
- 文字列はString、整数はintといったプリミティブ型で定義する
上のデータ型とインターフェースをを定義したものがソースコード1です。行数の関係から、BookInfoとBookSearcherのみを掲載しています。
ソースコード1.Javaによるインターフェース定義
package com.yone.soa.book;
import java.io.Serializable;
public class BookInfo implements Serializable {
private static final long serialVersionUID = -4277334378818084483L;
private String title;
private String subtitle;
private String author;
private String publisher;
private String isbn;
private String picture;
private int price;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
|
package com.yone.soa.book.service;
import java.rmi.RemoteException;
import com.yone.soa.book.BookInfo;
import com.yone.soa.book.SearchBooksResult;
public interface BookSearcher {
public String
getCategories(String initial)
throws RemoteException;
public SearchBooksResult
searchBooksByCategory(String category)
throws RemoteException;
public BookInfo
getBookByISBN(String isbn)
throws RemoteException;
}
|
業務アプリケーションに携わる人は、このプログラムコードにアクセスするのはとても簡単でしょう。標準的なJavaの文法を知っているだけでプログラミングが可能なはずです。
ソースファイルを含むZIPファイルが
こちら
からダウンロードできます。
XMLから定義する
では、WSDLでこの抽象インターフェースを定義してみましょう。テキスト・エディターを使ってWSDLを書くのは大変なので、WSDL専用のエディターを使います。ここではRAD(RationalApplication
Developer for WebSphere)に搭載されているWSDLエディターを使います。
このやりかたでは二つのステップで行います。それは、XMLスキーマ・データ型(XSDファイル)を作ることと、WSDLを作ることです。XMLスキーマは、これまた最初から作ると大変なので、サンプルXMLを作ってそこから生成しましょう。
サンプルになるXMLファイルを作る
RAD上のプロジェクト(なんでもかまいません)にとりあえずWSDLとかいう名前のフォルダーを作ってください。そして、フォルダー上で右クリックし、「新規」-「その他」を選択し、「すべてのウイザードを表示」にチェックを入れて、「XML」-「XML」を選択します。ウィザードで「XMLファイルを最初から作成」にチェックを入れて「次へ」ボタンをクリックします。
図1. XMLファイルの作成
ファイル名に「BookInfo」を入力して「終了」ボタンをクリックします。
図2. XMLファイル名の指定
空のXMLファイルが開きますので、書籍情報にあたるXMLがどんなカタチになるかを示すために、次のように書き込みます。
<?xml version="1.0" encoding="UTF-8"?>
<BookInfo>
<title>aaaa</title>
<subtitle>bbbb</subtitle>
<author>cccc</author>
<publisher>dddd</publisher>
<isbn>eeee</isbn>
<picture>fffff</picture>
<price>1234</price>
</BookInfo>
|
エディターを閉じて(Ctrl+F4)保存します。
XMLスキーマを生成する
今作ったファイルを右クリックして、「生成]-「XMLスキーマ」を選択します。ファイル名はきっと「BookInfo.xsd」となります。「終了」ボタンをクリックしてください。「XMLスキーマが正常に生成されました。」と出力されればうまくいってます。
さて、ここですこし調整しなければなりません。最初にすべきなのは接頭部と名前空間を与えることです。ここでは、便宜上、接頭語「Q1」、名前空間を「http://www.yone.com/xsd/books」とします。
図3. 接頭部と名前空間の指定
アウトライン・ビューを見てください。なにもしないと、すべての要素が文字列データとなります。しかし、price要素だけは整数に変更しなければなりませんね。そこで、アウトライン・ビューの「エレメント」-「price」をクリックして選択し、プロパティー・ビューを見てください。「型」というところに「xsd:string」と表示されていますね。その右側の
マークをクリックして、「組み込み単純型」の「xsd:int」を選択してください。
図4. 型の指定
図5. int型に変更したところ
同様の方法で、他のスキーマも作成します。BookInfo、SearchBooksResultItem、Customer、BookOrderItemはプリミティブ型のみでできているので同じ手順で作れます。接頭語、名前空間は同じもので結構です。
さて、他のスキーマを取り込み、配列であるものはどうしましょうか。たとえば、SearchBooksResultがそうです。これに関しては次のようにサンプルを作ってXSDを生成します。
<?xml version="1.0" encoding="UTF-8"?>
<SearchBooksResult>
<resulttotal>1</resulttotal>
<results>
<SeachBooksResultItem></SeachBooksResultItem>
<SeachBooksResultItem></SeachBooksResultItem>
<SeachBooksResultItem></SeachBooksResultItem>
<SeachBooksResultItem></SeachBooksResultItem>
</results>
</SearchBooksResult>
|
次に、XSDから別のXSDを参照させなければいけません。XSDを生成してXSDエディターが開いたら接頭語と名前空間を設定します。次にアウトライン・ビューの「ディレクティブ」を右クリックし、「インポートの追加」を選択します。すると、<import>タブが追加されます。アウトライン上には「ロケーション(位置のこと)が指定されていません」と表示されていますので、それを選択し、プロパティー・ビュー上でスキーマ位置の右側のボタンをクリックして「ワークベンチ・プロジェクト」から、先に作成した「SearchBooksResultItem.xsd」を選択します。
注:インクルードは同じ名前空間の場合、インポートは違う名前空間の場合に指定します。
このままだと、SearchBooksResultItemが、前のファイルとこのファイルの両方に存在してしまいます。最後にアウトライン・ビューから、SearchBooksResultItemのエレメントを削除します。
図6. 重複エレメントを削除する
これで終了です。SearchBooksResult.xsdは、SearchBooksResultItem.xsdを参照しており、itemsのしたには、配列が入ります。カテゴリーの配列も同じように作成しておく必要があります。CategoryArrayの下にcategoryが並ぶように作成してください。
同じやりかたでBookOrder.xsdを作ります。
WSDLを作る
すべてのデータ項目のXMLサンプルとXSDファイルを作成したら、WSDLの作成にとりかかります。今度は、新規ファイルとして「Webサービス」-「WSDL」を選択します。「BookSearcher.wsdl」と名前をつけましょう。
WSDLエディターの基本は、各区画ごとに「右クリックして追加」を繰り返していくことです。すでに、リクエスト-レスポンス型の操作が定義されていますので、これをそのまま使います。
XSDを参照する定義を加えます。「インポート」の区画で右クリックし、インポートの追加を選択して、BookInfo、BookSearchResultを追加します。
図7. インポートの追加
あとは、右下のポートタイプとメッセージの区画での作業となります。既存のものは、クリックしてプロパティー・ビューで名前などを調整します。メッセージに関しては、正しい型を指すように変更します。ポート・タイプ上に操作を追加し、同じ作業を繰り返します。
出来上がったファイルのgetBookByISBNResponseと、searchBooksByCatagoryの部分を展開した表示を掲載します。
図8. BookInfo部分
図9. SearchBooksResult部分
これで完成です。ここまで作業したWSDLファイルは
こちら
からダウンロードできます。
今回解説したように、抽象インターフェースはJava言語や、XMLスキーマとともにWSDLなどで定義することができます。
WSDLで定義したインターフェースをもとに、Webサービスを作る手順が
こちらに
あります。
著者について  | |  | 1987年に日本アイ・ビー・エム入社。メインフレームOS、ミドルウェアの障害対応、障害解析ソフトウェアの開発、ワークフローシステム開発、オブジェクト指向開発、Web開発など経験。2000年より、ソフトウェアのテクノロジーエバンジェリストとして活動中。 |
記事の評価
|