本文へジャンプ

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


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

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

  • 閉じる [x]

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

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

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


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

  • 閉じる [x]

IBM Lotus Domino 7 での実用的 Web サービス: 複雑な Web サービスを作成する

Julian Robichaux, Developer, Independent Consultant
Julian Robichaux は、ソフトウェア開発者であると同時に、IBM Lotus Notes と Java 開発を専門とするプロのプログラマーで、開発、アーキテクチャー、トレーニングが関わる大小のプロジェクトに契約ベースで参加しています。余暇は、個人の Web サイト/ブログ (http://www.nsftools.com) に費やしています。彼の家族は、どうして彼がどこに行くにもラップトップと一緒なのか理解できませんが、それは本人にしても同じことです。

概要: IBM Lotus Domino による Web サービスについての最後の記事である連載第 3 回では、複合データ型や列挙、ファイル添付、カスタム・フォールトなどの Domino Web サービスを使う上での高度な手法について解説します。

このシリーズの他の記事を見る

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


この連載第 1 回の「Practical Web services in IBM Lotus Domino 7: What are Web services and why are they important?」では、Web サービスの基本と SOA の用語を解説しました。また第 2 回「IBM Lotus Domino 7 での実用的 Web サービス: 単純な Web サービスを作成してテストする (Practical Web services in IBM Lotus Domino 7: Writing and testing simple Web services)」では、Lotus Domino V7 で単純な Web サービスを作成し、テストするための詳細について、要点を説明しました。この第 3 回の最後の記事では、Lotus Domino V7 を使って複雑な (そして実用的な) Web サービスを作成するための方法について解説します。

この記事で解説する例は、ダウンロードできる Notes データベースの中にあります (この記事の最後にある「ダウンロード」セクションを参照してください)。前回の記事と同じく、この記事で取り上げるサンプル・コードはすべて LotusScript で作成されています。しかし、この記事に付属のサンプル・データベースには、それらと等価な Java によるサンプルも含まれています。またこのデータベースの中には、Web サービスを呼び出し、テストするために使用できるサンプル・エージェントもいくつか含まれています。

複合データ型について

これまで扱ってきたのは、ストリングや整数、単純配列など、単純なパラメーターと戻り値のみでした。また、InOut パラメーターを使って複数の値を返す方法についても説明しました。しかし、より高度な Web サービスを開発しようとすると、すぐにデータ構造全体を送受信しなければならない状況に陥るものです。これは、XML 文書では頻繁に起こります。例えば次の例を見てください。


リスト 1. XML book の構造の例
                
<book>
    <author>Barry Allen</author>
    <title>Life in the Fast Lane</title>
    <booktype>Biography</booktype>
</book>

このような構造を使うと、<book> オブジェクト全体を、パラメーターあるいはレスポンスとして容易に送受信することができます。さらに、次のようにネスト構造を作ることもできます。


リスト 2. XML bookshelf の構造の例
                
<bookshelf>
    <shelfnumber>1</shelfnumber>
    <location>JLA Main Office</location>
    <book>
        <author>Barry Allen</author>
        <title>Life in the Fast Lane</title>
        <booktype>Biography</booktype>
    </book>
    <book>
        <author>Bruce Wayne</author>
        <title>Dark Times</title>
        <booktype>Reference</booktype>
    </book>
</bookshelf>

LotusScript では、カスタム型あるいはカスタム・クラスを使うことで、これを行うことができます。Web サービスでは、複合データ型と呼ばれるオブジェクトを使うことができます。

複合データ型のプロパティーがアルファベット順に並んでいることを確認する

LotusScript 複合データ型のプロパティーがアルファベット順に並んでいることを確認してください。なぜか理由はわかりませんが、一部のクライアント (例えば Apache Axis や Apache SOAP) では、LotusScript 複合データ型のプロパティーがアルファベット順でないと問題が起こります。プロパティーがアルファベット順に並んでいないと、リクエストまたはレスポンスの中にある複合データ型のデータ要素が一部失われてしまう場合があります。

LotusScript Web サービスでの複合データ型は、1 つ以上の public プロパティーを持つ public クラスにすぎません。各 public プロパティーは、複合データ型の要素として現れます。例えば <book> 構造を LotusScript クラスとしてモデル化するためには、次のようなコードを書きます。


リスト 3. LotusScript book クラスの例
                
Class Book
	Public author As String
	Public booktype As String
	Public title As String
End Class

これは、WSDL ファイルの中では下記のような構造として反映されます。


リスト 4. LotusScript book クラスに対する WSDL 複合データ型定義の例
                
<complexType name="BOOK">
    <sequence>
        <element name="AUTHOR" type="xsd:string"/>
        <element name="BOOKTYPE" type="xsd:string"/>
        <element name="TITLE" type="xsd:string"/>
    </sequence>
</complexType>

WSDL ファイルでは、データ型の名前とプロパティーがすべて大文字に変換されていることに注意してください。LotusScript は大文字小文字を無視しますが Web サービスは区別するため、Lotus Domino が LotusScript Web サービスを処理する場合、この変換を行います。

LotusScript Web サービスで複合データ型を使うと、次のようなシグニチャーを持つメソッドを作ることができます。


リスト 5. book クラスを使った LotusScript メソッドの例
                
Public Function findTitle (searchString As String) As Book
Public Sub uploadNewBook (newBook As Book)

この方が、送受信が必要なパラメーターを大量に持つメソッドよりも、ずっと管理が容易です。


サンプル・データベース: Web Services Bookstore

この記事で使用するサンプル・データベース (「ダウンロード」セクションにリンクがあります) は、Web サービスを使った書店データベースです。本の内容を含むファイルの検索やダウンロード、アップロードを、Web サービスを使って行うことができます。このデータベースには、Project Gutenberg によるパブリック・ドメインの eText ファイルがいくつか事前に入れられています。

図 1 は、このデータベースの中の文書の一例を示しています。


図 1. Web Services Bookstore サンプル・データベースの中の文書

これを見ると、それぞれの book 文書に標題 (title) と著者 (author)、本の種類 (book type)、備考 (description)、そして添付ファイルがあることがわかります。

このデータベースには、次のような 2 つの LotusScript Web サービスがあります。

  • BookSearch: 本を検索すると、本の標題と著者、本の種類、そして備考を返します。
  • BookDownloadUpload: 添付ファイルを含めて、本に関する情報を取得します。また、新しい本のファイルをアップロードすることもできます。

この記事のこれから先では、この 2 つの Web サービスのコードについて解説します。 2 番目のサービスではファイルのアップロードやダウンロードができ、また列挙と呼ばれる Web サービスのデータ構造を使用するため、このサービスの方が最初のサービスよりも複雑です。


BookSearch Web サービスの内部

BookSearch Web サービスでは本を検索することができ、また標題や著者、本の種類、備考など、単純な情報を取得することができます。常に 1 冊の本に関する情報を返すメソッドに対しては、BookInfo 複合データ型が返されます。1 冊以上の本に関する情報を返すメソッドに対しては、BookInfoArray 複合データ型が返されます (BookInfoArray には、BookInfo オブジェクトの配列と、その配列がいくつの項目を含むべきかを示す 1 つの要素が含まれています)。

下記は、LotusScript での BookInfo クラスの一般的な構造を示しています。


リスト 6. LotusScript BookInfo クラス
                
Class BookInfo
	Public author As String
	Public description As String
	Public fileName As String
	Public noteID As String
	Public title As String
	Public typeOfBook As String
End Class

ここで、データベースの book 文書のフィールドあるいは情報にマップされる、いくつかのデータ要素があります。返されるものの 1 つに、文書の NoteID があります。いくつかの標題を含む BookInfoArray を受信した後で 1 つの標題を取得する際には、NoteID を使えば簡単です。

このクラスの中には、ヘルパー・メソッドもあります。


リスト 7. LotusScript BookInfo クラスの中のgetDocContents メソッド
                
Public Function getDocContents (doc As NotesDocument) As Integer
	title = doc.GetItemValue(TITLE_FIELD)(0)
	description = doc.GetItemValue(DESCRIPTION_FIELD)(0)
	author = doc.GetItemValue(AUTHOR_FIELD)(0)
	typeOfBook = doc.GetItemValue(BOOK_TYPE_FIELD)(0)
	noteID = doc.NoteID
	'** firstAttachmentFileName is a custom Function to get
	'** the file name of the attachment on this document
	fileName = firstAttachmentFileName(doc, ATTACHMENT_FIELD)
	getDocContents = True
End Function

このデータベースの中から NotesDocument オブジェクトを取り出し、その情報をこの BookInfo オブジェクトの public プロパティーの中に読み込む際には、この関数が便利です。このメソッドは、public であるにもかかわらず、複合データ型定義のどこにも現れないことに注意してください。複合データ型で利用できるのは public プロパティーのみです。

下記は、BookInfoArray オブジェクトの一般的な構造を示しています。


リスト 8. LotusScript BookInfoArray クラス
                
Class BookInfoArray
	Public bookArray() As BookInfo
	Public count As Integer
End Class

bookArray プロパティーは BookInfo オブジェクトの配列であり、また count プロパティーは、bookArray 内に含まれるべき要素の数です。厳密に必要なことではありませんが、このような配列と対応するように count プロパティーをインクルードすると、とても便利なことがわかっています。そうすることで、その配列が空かどうかを Web サービス・クライアントが容易に判断できます。つまり Web サービス・クライアントは、count がゼロ (空) か正の数 (空ではない) かを単純にチェックするだけでよいのです。こうしておかないと、空の配列がヌル・オブジェクトなのか、要素を持たない配列なのか、あるいはヌルまたは空の値を含む 1 つのオブジェクトなのか、わからなくなる恐れがあります。

BookInfoArray クラスも、ヘルパー・メソッドを持っています。


リスト 9. LotusScript BookInfoArray クラスの setArrayFromCollection メソッド
                
Public Sub setArrayFromCollection (dc As NotesDocumentCollection)
	count = dc.Count
	If (count = 0) Then
		Redim bookArray(0)
	Else
		Redim bookArray(count - 1)
		
		Dim doc As NotesDocument
		Dim dcCount As Integer
		Set doc = dc.GetFirstDocument
		Do Until (doc Is Nothing)
			Dim book As New BookInfo
			Call book.getDocContents(doc)
			Set bookArray(dcCount) = book
			Set doc = dc.GetNextDocument(doc)
			dcCount = dcCount + 1
		Loop
	End If
	
End Sub

BookInfo クラスの getDocContents メソッドと同様、このメソッドは、このデータベースの Book 文書の NotesDocumentCollection を取り出し、このコレクションの中の各 NotesDocument を内部の bookArray プロパティーに追加します。また、このコレクションの中にある文書の数に基づいて、count プロパティーを適切に設定します。


フォールトをスローし、エラーを処理する

BookSearch クラスを検証する前に、少し休憩して LotusScript Web サービスでのフォールトの概念について説明しましょう。

Web サービスの用語では、フォールトはエラーです。もし LotusScript Web サービスにフォールト生成やエラー処理がなかったとすると、このサービスのメソッドをコールしてエラーが発生すると、次のような SOAP レスポンスを受信することになります。


リスト 10. 汎用の LotusScript SOAP フォールト
                
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>soapenv:Server.generalException</faultcode>
         <faultstring>LotusScript did not run to completion.</faultstring>
         <detail/>
      </soapenv:Fault>
   </soapenv:Body>

発生した実際のエラーは、サーバー・コンソールと log.nsf ファイルに現れますが、残念なことにユーザーに返されるフォールトは非常に一般的なものであり、あまり役に立ちません。

エラーが発生した際には、(必ずとは言えませんが) 独自のフォールトを生成したいと思うのが普通です。そうでないと、Web サービスは値を返すことができません。そこで、いわゆる明示的フォールト処理をメソッドに追加します。その手順は以下のとおりです。

  1. Web サービス・コードの Options セクションに %INCLUDE "lsxsd.lss" という行があることを確認します。
  2. WS_FAULT パラメーターを、そのメソッドの最後のパラメーターとして追加します (WS_FAULT は最後のパラメーターでなければなりません)。
  3. エラーが発生したら、あるいはユーザーにフォールトを返したい場合には、WS_FAULT オブジェクトを設定し、そのメソッドを Exit 関数または Exit サブステートメントで終了します。

下記はその一例です。


リスト 11. 明示的な LotusScript フォールトをスローする例
                
Public Function stringToNumber (s As String, returnFault As WS_FAULT) As Integer
	On Error Goto processError
	stringToNumber = Cint(s)
	Exit Function
	
processError:
	Call returnFault.setFault(True)
	Call returnFault.setFaultString(Error$)
	Messagebox "Logging to console: " & Error$
	Exit Function
End Function

クライアントが stringToNumber メソッドをコールする場合、クライアントには 1 つのストリング・オブジェクトが stringToNumber メソッドに渡されることしか見えません。フォールト・パラメーターは、隠れて見えません。しかし、もしエラーが発生すると、フォールト・メッセージを任意に設定することができます。この例では、もしクライアントが偽の値 (例えば foo) をこのメソッドに渡すと、クライントは次のようなレスポンスを受信します。


リスト 12. 明示的に生成されたフォールトによって返される SOAP フォールト
                
				
<soapenv:Fault>
    <faultcode>soapenv:Server.generalException</faultcode>
    <faultstring>Type mismatch</faultstring>
    <detail/>
</soapenv:Fault>

ヒント: フォールト生成メソッドを使う

In the BookSearch and BookDownloadUpload フォールトを生成する必要がある場合、BookSearch クラスと BookDownloadUpload クラスでは別のメソッドをコールします。これによって、Web サービスでフォールトが発生した場合に、容易にグローバルなロギングあるいは通知を追加することができます。

この場合の <faultstring> 要素の方が、汎用のメッセージ「LotusScript did not run to completion」よりも、ずっと具体的です。

stringToNumber メソッドの processError ブロックに関しては、他にも 2 つ注意すべきことがあります。

  • setFault を使って、フォールト・オブジェクトを明示的に True に設定する必要があります。
  • Messagebox ステートメントはオプションですが、Messagebox ステートメントがあるということは、Web サービスを実行している任意の時点で、Messagebox ステートメントを使ってサーバー・コンソールと log.nsf ファイルにエラー (あるいは他の情報) を書き出せるということです。これは単純なデバッグやロギングの際に便利です。

BookSearch クラスの構造

では、BookSearch Web サービスの例に戻りましょう。この Web サービスのインターフェースとして公開される BookSearch クラスは、次の 3 つの public メソッドを持っています。

  • getFirstTitleMatch: 与えられた検索ストリングに一致する標題を持つ最初の本に関する 1 つの BookInfo オブジェクトを返します。
  • getAllTitleMatches: 与えられた検索ストリングに一致する標題を持つすべての本に関する BookInfoArray オブジェクトを返します。
  • getDocByNoteID: 指定された NoteID の book 文書に関する 1 つの BookInfo オブジェクトを返します。

また、次の 2 つの private ヘルパー・メソッドがあります (Web サービス・クライアントには利用できません)。

  • throwFault: メソッドがフォールトを生成する必要がある場合、メソッドがフォールトを作成する共通の方法を提供する必要がある場合、そしてメソッドがすべての返されるフォールトをログする必要がある場合に、そのメソッドによってコールされます。
  • findDocsByTitle: このデータベースの中の、与えられた検索ストリングに一致する book 文書を含む NotesDocumentCollection を返します。

findDocsByTitle メソッドは基本的な NotesView 検索関数ですが、throwFault メソッドの方は調べるだけの価値があります。以下は、そのコードです。


リスト13. LotusScript BookSearch クラスの throwFault メソッド
                
Private Sub throwFault (fault As WS_FAULT, faultText As String)
	Call fault.setFault(True)
	Call fault.setFaultString(faultText)
	'** do any other error logging things here...
End Sub

先ほどのフォールトの例でも同じことをしましたが、個々の Web サービス・メソッドの中でフォールト・プロパティーを設定するのではなく、それぞれのメソッドにこの関数をコールさせています。こうすることの利点は、この関数の最後のコメントにあるとおりです。つまり、「do any other error logging things here (他のすべてのエラー・ロギングをここで行う)」ということです。

このようなルーチンを使ってフォールトを生成することによって、Web サービスで発生するフォールトの管理やログを行う中心となる場所を容易に提供することができます。Messagebox ステートメントを使ってサーバー・コンソールにメッセージを書き出したり、中心となる NotesLog に書き出したり、さらには OpenLog のようなカスタムのエラー・ログ・データベースを使うこともできます。この場合も、フォールト処理のために必ず別メソッドが必要なわけではありませんが、そうした方が適切です。

BookSearch クラスの public メソッド群に関するコードは、以下のとおりです。


リスト 14. Web サービスの実装として使われる LotusScript BookSearch クラス
                
Public Function getFirstTitleMatch (searchString As String, _
returnFault As WS_FAULT) As BookInfo
	On Error Goto processError
	Dim dc As NotesDocumentCollection
	Set dc = findDocsByTitle(searchString)
	
	If (dc.Count = 0) Then
		Call throwFault(returnFault, "No matches found for search string: " & searchString)
		Exit Function
	End If
	
	Set getFirstTitleMatch = New BookInfo
	Call getFirstTitleMatch.getDocContents(dc.GetFirstDocument)
	Exit Function
	
processError:
	Call throwFault(returnFault, "Error searching documents: " & Error)
	Exit Function
	
End Function

Public Function getAllTitleMatches (searchString As String, _
returnFault As WS_FAULT) As BookInfoArray
	On Error Goto processError
	Dim dc As NotesDocumentCollection
	Dim doc As NotesDocument
	Set dc = findDocsByTitle(searchString)
	
	Set getAllTitleMatches = New BookInfoArray
	Call getAllTitleMatches.setArrayFromCollection(dc)
	
	Exit Function
	
processError:
	Call throwFault(returnFault, "Error searching documents: " & Error)
	Exit Function
	
End Function

Public Function getDocByNoteID (noteID As String, _
returnFault As WS_FAULT) As BookInfo
	On Error Resume Next
	Dim session As New NotesSession
	Dim db As NotesDatabase
	Dim doc As NotesDocument
	
	Set db = session.CurrentDatabase
	Set doc = db.GetDocumentByID(noteID)
	If (doc Is Nothing) Then
		Call throwFault(returnFault, "No doc found for Note ID " & noteID)
		Exit Function
	End If
	
	Set getDocByNoteID = New BookInfo
	Call getDocByNoteID.getDocContents(doc)
End Function

これらのメソッドのコードは非常に短く、理解しやすいのですが、次のようないくつかの点に注意する必要があります。

  • getFirstTitleMatch メソッドと getDocByNoteID メソッドは検索が空の場合にフォールトを生成しますが、getAllTitleMatches は LotusScript エラーがある場合にしかフォールトを生成しないことに注意してください。これはつまり、本当のランタイム・エラーが起きていなくてもフォールト・オブジェクトを返せる、ということです。またこの場合には、空の BookInfo オブジェクトを返すこともできます。
  • BookInfo.getDocContents メソッドと BookInfoArray.setArrayFromCollection メソッドのコードの短さから、これらのコードが使いやすいものであることがわかります。こうしたヘルパー・メソッドを複合データ型クラスの中に含めることによって、Web サービスのコードを短くできるだけではなく、重要なところにちょっとした一般的な機能を追加したり、そうした機能を修正したりすることもできます。

Web サービスのメソッドをテストする場合には、Web Services Bookstore データベースのテスト・エージェントを使うか、あるいは前回の記事「IBM Lotus Domino 7 での実用的 Web サービス: 単純な Web サービスを作成してテストする (Practical Web services in IBM Lotus Domino V7: Writing and testing simple Web services)」で解説した方法の中の 1 つを使います。


列挙を使う

BookDownloadUpload Web サービスのコードについて説明する前に、もう 1 つのデータ構造について説明しておく必要があります。それは、列挙と呼ばれる構造です。

列挙は Lotus Domino V7.0.1 以降でないと使えません

Lotus Domino V7.0.1 以降を実行する場合以外は、列挙を使うべきではありません。Lotus Domino V7.0 の最初のリリースでは列挙の処理に問題があり、列挙に対して想定され、返されるデータ型が正しくありませんでした。この問題はリリース 7.0.1 では解決されています。

列挙は、Web サービス・メソッドのパラメーターとして使われる、あるいは複合データ型の要素として使われる項目の、単なる固定リストです。この書店の例で許されているのは、次の 4 種類のみです。

  • フィクション (Fiction)
  • ノンフィクション (Non-fiction)
  • 参考資料 (Reference)
  • 漫画 (Comic book)

Domino フォームあるいは Web ページの場合は、ユーザーが制限付きフィールドに勝手なデータを追加できないように、こうした入力を選択リストを使ってコントロールすることができます。Web サービスの場合は、列挙を使います。WSDL 文書では、列挙は次のようになります。


リスト 15. WSDL 文書の中で列挙がどのように見えるかを示す例
                
<simpleType name="BOOKTYPE">
    <restriction base="xsd:string">
        <enumeration value="Fiction"/>
        <enumeration value="Non-Fiction"/>
        <enumeration value="Reference"/>
        <enumeration value="Comic Book"/>
    </restriction>
</simpleType>

こうした種類の列挙によるパラメーターや複合データ型を使用する Web サービス・クライアントは、列挙定義の中にリストされている値でないと、値として渡すことができません。それ以外の値はすべて、クライアント・コードでエラーを生成するか、あるいは Web サービスが呼び出されるとフォールトを生成します。

LotusScript で列挙構造を生成するためには、いくつかのことを非常に厳密に行う必要があります。一例として、下記は BookDownloadUpload Web サービスの BookType 列挙のコードを示しています。


リスト 16. LotusScript BookType列挙のコード
                
'** These constant names MUST begin with "BookType_":
Const BookType_Fiction = "Fiction"  
Const BookType_Nonfiction = "Non-Fiction"
Const BookType_Reference = "Reference"
Const BookType_Comic = "Comic Book"


'** These global variable names MUST end with "_BookType":
Dim Fiction_BookType As BookType
Dim NonFiction_BookType As BookType
Dim Reference_BookType As BookType
Dim Comic_BookType As BookType


'** This list of possible BookTypes MUST be called "Enum_BookType":
Dim Enum_BookType List As BookType 


'** The actual BookType enumeration class:
Class BookType
	'** we MUST have a Public property called "Value",
	'** of the same data type as the Const values above
	Public Value As String
	
	Public Sub Initialize (typeString As String)
		Value = typeString
		Set Enum_BookType(Cstr(Value)) = Me
	End Sub
End Class

'** This class will initialize all the global _BookType objects.
'** Is should be called when the BookDownloadUpload class is instantiated.
Class BookTypeInitializer
	Public Sub New ()
		Set Fiction_BookType = New BookType
		Call Fiction_BookType.Initialize(BookType_Fiction)
		
		Set NonFiction_BookType = New BookType
		Call NonFiction_BookType.Initialize(BookType_NonFiction)
		
		Set Reference_BookType = New BookType
		Call Reference_BookType.Initialize(BookType_Reference)
		
		Set Comic_BookType = New BookType
		Call Comic_BookType.Initialize(BookType_Comic)
	End Sub
End Class

LotusScript で列挙を作成するためには、以下を行う必要があります。

  1. 列挙の名前を決定します (ここでは BookType とします)。
  2. 列挙の中の各項目に対して、グローバルな Const 変数を作成します。それぞれの Const 名は、最初に列挙名、その後に下線が続きます (ここでは BookType_xxx です)。
  3. 列挙の中の各項目に対してグローバル・オブジェクトを作成します。このオブジェクト名のデータ型は列挙名に等しく、各オブジェクト名は下線の後に列挙名が続いて終わります (ここでは xxx_BookType です)。
  4. グローバル・リストを作成します。このリストのデータ型は列挙名に等しく、また名前は Enum_ の後に列挙名が続きます (ここでは Enum_BookType です)。
  5. 列挙名と同じ名前を持つカスタム・クラスを作成します。このクラスは、Value と呼ばれる 1 つの public プロパティーを持つ必要があります。そしてこのプロパティーのデータ型は、(ステップ 2 で) この列挙のために作成した Const 変数と同じデータ型である必要があります。
  6. Web サービスがコールされたら、(この場合は BookTypeInitializer クラスのインスタンスを作成することによって) すべてのグローバル列挙オブジェクトを適切な値で初期化するコードを実行します。

それが終了すれば、ステップ 5 で作成したカスタムの列挙クラスを、その列挙を使おうとする場所のどこででも使えるようになります。このクラスは WSDL ファイルの中では列挙要素として現れ、また値に関して、ステップ 4 の Enum リストで指定される制限が適用されます。

こうすると、クライアントが使うことができる制限付きの値のリストを生成するには、かなり特定的なコードを大量に作成しなければなりません。しかし一方でこれは、そうしたリストを Web サービスで処理する上での適切な方法でもあるのです。

このコード作成プロセスを容易にするために、Domino Enumeration Code Generator ページ を試してみてください。ここには、列挙名やデータ型、そしてこれから使おうとするあらゆる値を入力することができます。またこのページは、LotusScript と Java のコードを生成してくれます。これによって、Lotus Domino で Web サービス列挙をすぐに使い始めることができます。


BookDownloadUpload Web サービスの内部

Web Services Bookstore データベースの中にある、もう 1 つの Web サービスが、BookDownloadUpload サービスです。このサービスを利用すると、この書店の book 文書に関する情報を取得できるだけではなく、1 冊、あるいは 1 冊以上の本の内容を含んだファイルをダウンロードすることもできます。さらに、このサービスを使って、新しい本をアップロードすることもできます。この Web サービス・コードには、次の 4 つの主なコンポーネントがあります。

  • BookType 列挙: これに関しては既に説明しました。
  • BookInfoAndFile 複合データ型: これは本に関する情報とファイル・データを含んでいます。
  • BookInfoAndFileArray 複合データ型: これは BookInfoAndFile オブジェクトの配列です (ちょうど BookSearch サービスの BookInfoArray 型と同じです)。
  • BookDownloadUpload クラス: この Web サービスに関するインターフェース・クラスです。

BookType 列挙については、この前のセクションで概要を説明しました。BookInfoAndFileArray クラスは、基本的に BookSearch サービスの BookInfoArray クラスと同じです。BookInfoAndFile クラスと BookDownloadUpload クラスに関しては、後ほど詳しく説明します。


ファイル添付を処理する

BookDownloadUpload サービスと BookSearch サービスとの大きな違いは、BookDownloadUpload サービスではファイルをアップロード、ダウンロードできる点です。そのためには、lsxsd.lss ファイルで定義される XSD_BASE64BINARY クラスを使います。

最初に、BookInfoAndFile クラスのコードを下記に示します。


リスト 17. LotusScript BookInfoAndFile クラス
                
Class BookInfoAndFile
	Public author As String
	Public base64file As XSD_BASE64BINARY
	Public description As String
	Public fileName As String
	Public noteID As String
	Public title As String
	Public typeOfBook As BookType
	
	'** instantiate the base64file object on creation
	Public Sub New ()
		Set base64file = New XSD_BASE64BINARY
	End Sub
	
	'** shortcut way to set the contents of the base64file field
	'** from a NotesStream
	Public Sub setFile (stream As NotesStream)
		Call base64file.SetValueFromNotesStream(stream)
	End Sub
	
	'** shortcut way to get the contents of the base64file field
	'** as a NotesStream
	Public Function getFile () As NotesStream
		Set getFile = base64file.GetValueAsNotesStream()
	End Function
	
	'** shortcut way to set the contents of the typeOfBook field
	Public Sub setBookType (bookTypeString As String)
		Set typeOfBook = Enum_BookType(bookTypeString)
	End Sub
	
	'** shortcut way to get the contents of the typeOfBook field
	Public Function getBookType () As String
		getBookType = typeOfBook.toString()
	End Function
	
	'** take a NotesDocument from this database and populate the
	'** values of the Public properties based on its field values
	Public Function getDocContents (doc As NotesDocument) As Integer
		title = doc.GetItemValue(TITLE_FIELD)(0)
		description = doc.GetItemValue(DESCRIPTION_FIELD)(0)
		author = doc.GetItemValue(AUTHOR_FIELD)(0)
		
		Call setBookType(doc.GetItemValue(BOOK_TYPE_FIELD)(0))
		
		'** custom functions to convert an attachment to a NotesStream
		fileName = firstAttachmentFileName(doc, ATTACHMENT_FIELD)
		Call setFile(firstAttachmentToStream(doc, ATTACHMENT_FIELD))
		
		noteID = doc.NoteID
		getDocContents = True
	End Function
	
	'** create a new document in this database, based on the contents
	'** of the Public properties in this object
	Public Function createNewDoc () As Integer
		Dim session As New NotesSession
		Dim doc As NotesDocument
		
		Set doc = New NotesDocument(session.CurrentDatabase)
		doc.Form = FORM_NAME
		Call doc.ReplaceItemValue(TITLE_FIELD, title)
		Call doc.ReplaceItemValue(DESCRIPTION_FIELD, description)
		Call doc.ReplaceItemValue(AUTHOR_FIELD, author)
		Call doc.ReplaceItemValue(BOOK_TYPE_FIELD, getBookType())
		
		Dim rtitem As New NotesRichTextItem(doc, ATTACHMENT_FIELD)
		Dim tempFileName As String
		'** custom function to write a NotesStream to a temp file
		tempFileName = createTempFile(fileName, Me.getFile())
		Call rtitem.EmbedObject(EMBED_ATTACHMENT, "", _
		tempFileName, fileName)
		
		Call doc.Save(True, False)
		noteID = doc.NoteID
		
		Kill tempFileName
		createNewDoc = True
	End Function
End Class

Base64file は添付ファイルを保持する public プロパティーなので、これを XSD_BASE64BINARY データ型として宣言します (WSDL ファイルでは xsd:base64Binary データ型として現れます)。この LotusScript データ型は lsxsd.lss ファイルの中で定義され、ファイル内容の取得、設定に使用される 2 つのメソッド (SetValueFromNotesStream と GetValueAsNotesStream) を持っています。

Java Base64 エンコーディング/デコーディングは LotusScript よりもずっと高速です

もし 20 KB よりも大きなファイルに base64 エンコーディングとデコーディングを使用するのであれば、Java (Java Web サービスまたは LS2J) を使ったエンコーディング処理を検討してください。LotusScript base64 ルーチンは、小さなファイルを処理する場合以外、特にデコーディング・ルーチンは非常に遅いのです。

サンプル・データベースの BookDownloadUpload Web サービスには、LS2J を使って base64 機能を処理する例が置いてあります。またサンプル・データベースには、全プロセスを Java で行う方法を示した BookDownloadUploadJava Web サービスもあります。

(SetValueFromNotesStream を使って) NotesStream がオブジェクトの中に読み込まれると、バイナリーまたは ASCII のデータ・ストリームを渡すことができます。そしてこのクラスは、データを base64 でエンコードしてくれます。同様に、オブジェクト内に保存されたファイル・データに関しては、(GetValueAsNotesStream を使うと) バイナリーの NotesStream としてデータを抽出でき、そして base64 デコーディングが処理されます。

そうすると問題は、NotesStream の処理になります。ローカル・ファイルシステムに対してファイルを読み書きするのであれば、ファイルをストリームに変換するのは非常に単純です (この例については Lotus Domino Designer の Help を参照してください)。NotesDocument または NotesRichTextItem の添付ファイルを NotesStream に変換するためには、まずそのファイルを取り出してからストリームに書き込む必要があります。同様に、NotesStream を添付として文書に付加する場合は、まずそのストリームを一時ファイルに書き込んだ後、その一時ファイルを文書に添付する必要があります。この Web サービスのカスタム関数、firstAttachmentToStream と createTempFile は、この処理を行います (その動作についてはサンプル・データベースのコードを参照してください)。

クライアント側では、ユーザーが添付ファイルを送信または受信する際には、クライアント・コード自体で base64 のエンコーディングとデコーディングを処理する必要があります。一部のクライアント (Apache Axis など) は、この処理を行います。他のクライアント (MSSOAP など) の場合は、皆さんが手動で処理する必要があるかもしれません。


BookDownloadUpload クラスの構造

BookDownloadUpload クラスは、先ほど見た BookSearch クラスと非常に似ています。このクラスには、次の 5 つのメソッドがあります。

  • getFirstTitleMatch: 与えられた検索ストリングに一致する標題を持つ最初の本に関する 1 つの BookInfoAndFile オブジェクトを返します。
  • getAllTitleMatches: 与えられた検索ストリングに一致する標題を持つすべての本に関する BookInfoAndFileArray オブジェクトを返します。
  • getDocByNoteID: 指定された NoteID の book 文書に関する 1 つの BookInfoAndFile オブジェクトを返します。
  • addNewFileComplex: これを使うことで、クライアントは BookInfoAndFile オブジェクトをアップロードして新しい book 文書を作成することができます。
  • addNewFile: これを使うことで、クライアントは book の個々の要素をすべて別々のパラメーターとして渡して新しい book 文書を作成することができます。

BookSearch クラスの場合と同じく、Web サービスのクライアントには利用できない 2 つの private ヘルパー・メソッド (throwFault と findDocsByTitle) があります。

下記は BookDownloadUpload クラスのコード・リストです。


リスト 18. Web サービスの実装として使われる LotusScript BookDownloadUpload クラス
                
				
Class BookDownloadUpload
	
	'** initialize all the global BookType objects before we start
	Public Sub New ()
		Dim bookInit As New BookTypeInitializer
	End Sub
	
	Public Function getFirstTitleMatch (searchString As String, _
	returnFault As WS_FAULT) As BookInfoAndFile
		On Error Goto processError
		Dim dc As NotesDocumentCollection
		Set dc = findDocsByTitle(searchString)
		
		If (dc Is Nothing) Then
			Call throwFault(returnFault, "No matches found for search string: " & searchString)
			Exit Function
		Elseif (dc.Count = 0) Then
			Call throwFault(returnFault, "No matches found for search string: " & searchString)
			Exit Function
		End If
		
		Set getFirstTitleMatch = New BookInfoAndFile
		Call getFirstTitleMatch.getDocContents(dc.GetFirstDocument)
		Exit Function
		
processError:
		Call throwFault(returnFault, "Error searching documents: " & Error)
		Exit Function
		
	End Function
	
	Public Function getAllTitleMatches (searchString As String, _
	returnFault As WS_FAULT) As BookInfoAndFileArray
		On Error Goto processError
		Dim dc As NotesDocumentCollection
		Dim doc As NotesDocument
		Set dc = findDocsByTitle(searchString)
		
		Set getAllTitleMatches = New BookInfoAndFileArray
		Call getAllTitleMatches.setArrayFromCollection(dc)
		
		Exit Function
		
processError:
		Call throwFault(returnFault, "Error searching documents: " & Error)
		Exit Function
		
	End Function
	
	Public Function getDocByNoteID (noteID As String, _
	returnFault As WS_FAULT) As BookInfoAndFile
		On Error Resume Next
		Dim session As New NotesSession
		Dim db As NotesDatabase
		Dim doc As NotesDocument
		
		Set db = session.CurrentDatabase
		Set doc = db.GetDocumentByID(noteID)
		If (doc Is Nothing) Then
			Call throwFault(returnFault, "No doc found for Note ID " & noteID)
			Exit Function
		End If
		
		Set getDocByNoteID = New BookInfoAndFile
		Call getDocByNoteID.getDocContents(doc)
	End Function
	
	Private Sub throwFault (fault As WS_FAULT, faultText As String)
		Call fault.setFault(True)
		Call fault.setFaultString(faultText)
		
		'** do any other error logging things here...
		If (Err > 0) Then
			'** Messagebox will write to log.nsf, just like a backend agent will
			Messagebox LogError()
		End If
	End Sub
	
	Private Function findDocsByTitle (searchString As String) As NotesDocumentCollection
		Dim session As New NotesSession
		Dim db As NotesDatabase
		Dim view As NotesView
		
		Set db = session.CurrentDatabase
		Set view = db.GetView(TITLE_LOOKUP_VIEW)
		Set findDocsByTitle = view.GetAllDocumentsByKey(searchString, False)
	End Function
	
	Public Function addNewFileComplex (book As BookInfoAndFile, _
	returnFault As WS_FAULT) As String
		On Error Goto processError
		Call book.createNewDoc()
		addNewFileComplex = book.noteID
		Exit Function
		
processError:
		Call throwFault(returnFault, "Error creating new doc: " & Error)
		Exit Function
		
	End Function
	
	Public Function addNewFile (title As String, author As String, description As String, _
	typeOfBook As BookType, fileName As String, base64file As XSD_BASE64BINARY, _
	returnFault As WS_FAULT) As String
		Dim book As New BookInfoAndFile
		book.title = title
		book.author = author
		Set book.typeOfBook = typeOfBook
		book.description = description
		book.fileName = fileName
		Set book.base64file = base64file
		addNewFile = addNewFileComplex(book, returnFault)
	End Function
	
End Class

これを見るとわかるように、getFirstTitleMatch メソッドと getAllTitleMatches メソッド、そして getDocByNoteID メソッドのコードは、(BookInfo オブジェクトではなく BookInfoAndFile オブジェクトを使うことを除いて) BookSearch クラスの同じ関数のコードと基本的に同じです。このリストでは、BookTypeInitializer クラスを使って列挙を初期化するコード行を New sub に追加してあります。また throwFault メソッドは、Messagebox を使ってサーバー・コンソールにエラー・メッセージを書き出す方法を示しています。これらを除けば、BookDownloadUpload クラスは BookSearch クラスと非常によく似ています。

addNewFile メソッドと addNewFileComplex メソッドには、ほとんどコードがありません。これは、アップロードされた book データからデータベースの中に新しい文書を作成するためのロジックは、既に BookInfoAndFile の中で作成されているためです。


サンプル・データベースをテストする

Web Services Bookstore サンプル・データベースのサービスのいずれかをテストする場合のために、(ファイルのダウンロードとアップロードを含めて) すべての Web サービス・メソッドをコールする 2 つのサンプル・エージェントがデータベースの中に用意されています。これらのエージェントは Java で書かれており、また OpenNTF.org で入手できるオープンソースの Stubby データベースによって生成された、Apache Axis スタブ・ファイルを使っています。

また、MSSOAP を使って単純に本の検索を行うサンプルも、いくつか含まれています。ただし、最新の MSSOAP 3.0 ライブラリーをインストールしておかないと、MSSOAP のサンプルは Web サービスを RPC/Encoded にした場合にしか動作せず、また BookDownloadUpload サービスを使った場合にも動作しません (MSSOAP 1.x は、このサービスで使用する BookType 列挙を解釈できないため)。MSSOAP を使う場合の制約の詳細については、前回の記事「IBM Lotus Domino 7 での実用的 Web サービス: 単純な Web サービスを作成してテストする (Practical Web services in IBM Lotus Domino V7: Writing and testing simple Web services)」を参照してください。

また、この連載のこれまでの記事で概要を説明した、他のテスト・ツールを使うこともできます。


注意点とトラブルシューティング

以下は、Web サービスのコードで問題が起きた場合に役に立つ、一般的な注意点とトラブルシューティングのガイドラインです。

ローカルでテストする場合には、Notes HTTP サービスが実行していることを確認する

テストしようとする Web サービスのデータベースにローカル・コピーがある場合には、まずバックグラウンドで Notes HTTP サービスが実行されていることを確認する必要があります。そのためには、下記のようにするのが最も簡単です。

  1. Domino Designer でデータベースを開く
  2. データベースのフォームまたはビューを選択する
  3. Design - Preview in Web browser - Default Browser を選択し、Web ブラウザーにフォームまたはビューが表示されるのを待つ

フォームまたはビューが Web ページとして表示されたらブラウザー・ウィンドウを閉じ、サーバー名を localhost として Web サービスをテストします。HTTP サービスは、Notes クライアントが完全に閉じられるまで、バックグラウンドで動作し続けます。

注意: 一部のパーソナル・ファイアーウォールは、ローカルの HTTP サービスの動作をブロックします。そのため、ファイアーウォールの設定を調整する必要があるかもしれません。

ユーザーに Web サービスに対するアクセス権がない場合、401 Access Denied エラーが発生する

その Web サービスにアクセスするためのセキュリティー要求をよく理解する必要があります。ある匿名ユーザーが WSDL ファイルを読もうとする場合、あるいは Web サービスのメソッドをコールしようとする場合、そのユーザーがデータベースと Web サービスに対して少なくとも Reader アクセス権を持っていないと、401 Access Denied エラーを受け取ることになります。Lotus Domino の最初の 7.0 バージョンでは、こうした場合に (少し明確さに欠ける) 404 Not Found エラーが生成されました。

Messagebox または System.out.println を使ってサーバー・コンソールに情報を出力する

サーバー・コンソール (そして log.nsf ファイル) に単純にメッセージをダンプする方法は、通常はロギング手法として適切ではありませんが、一時的なロギングを迅速に行いたい場合には便利です。Domino Web サービスでは、Messagebox (LotusScript の場合) あるいは System.out.println (Java の場合) を使って作られたメッセージは、サーバー・コンソールに送られます。

もちろん、もっと良いのは、NotesLog または OpenLog データベースのような汎用のロギング手法を使うことです。もし (この記事でのサンプル Web サービスのように) 中心的なメソッドを使ってフォールト生成の処理を行う場合には、そうしたロギング・システムへのコールを追加するだけで、容易にメッセージやエラーを追跡することができます。

Web サービスやファイル読み書きサービスをコールするサーバー・エージェントに対するランタイム・セキュリティー

ファイルを読み書きする Web サービスや、ネットワークにアクセスする Web サービス、あるいは Web サービスをコールするサーバー・ベースのエージェントに関しては、次のような条件が満足されていることを確認します。

  • そのエージェントまたは Web サービスの Runtime Security Level が、少なくとも「2. Allow Restricted Operations」であること (これは、エージェントまたは Web サービスの設計要素を編集する際に利用する Properties ボックスの中で設定できます)。
  • そのエージェントまたは Web サービスの署名者が、Server 文書に対して「Run unrestricted methods and operations (制限付きはでないメソッドやオペレーションを実行する)」権限を持っていること。
  • そのエージェントまたは Web サービスの署名者が、Server 文書に対して「Run restricted LotusScript/Java agents (制限付きの LotusScript/Java エージェントを実行する)」権限を持っていること。

こうした権限が適切に設定されていない場合、そのエージェントまたは Web サービスが実行されると、(通常はサーバー・コンソールと log.nsf ファイルの中に) セキュリティー・エラーが現れます。

Web サービスが error 500 を返す場合には LotusScript の再コンパイルが必要

WSDL ファイルをアクセスしようとすると、あるいは Web サービスのメソッドを実行すると、「Unknown LotusScript Error」メッセージと共に HTTP error 500 が受信される場合には、データベースの中のすべての LotusScript を再コンパイルする必要があります。このエラーがよく起こるのは、Web サービスがスクリプト・ライブラリーの関数を使っており、そのライブラリーが Web サービスよりも後に更新されている場合です。これは、Lotus Notes クライアントが「Error Loading USE or USELSX」メッセージを表示する場合の条件と似ています。

可変配列を固定配列に変換する

LotusScript Web サービスから配列を返す際には、動的な可変配列ではなく、必ず固定配列を返すようにします。例えば、次のようなタイプの LotusScript コールは可変配列を生成します。

  • varval = doc.SomeFieldName
  • varval = Split("I am superman", " ")
  • varval = Evaluate(|@DbColumn("";"":"somedatabase";"some view";2)|)

幸い、これは容易に解決できる問題です。次のようなコードを使えば、可変配列を固定配列に変換することができます。


リスト 19. 可変配列を固定配列に変換する LotusScript コード
                
Dim returnArray() As String
varval = doc.MultiValueCategoryField
Redim returnArray(Ubound(varval))
For i = 0 To Ubound(varval)
	returnArray(i) = varval(i)
Next

注意: 配列は、lsxsd.lss ファイルの中で定義される ARRAY_HOLDER データ型の 1 つとして返される必要があります (これに関しては、この連載の前回の記事で詳しく説明されています)。

Lotus Domino V7.0.1 以降を使う (特に、列挙を使う場合には)

Lotus Domino V7.0.1 では、微妙ながら重要ないくつかの問題が修正されています。最も注目すべき点として、最初の Lotus Domino V7.0 リリースには、列挙が適切に動作しないという問題がありました。Lotus Domino のバージョンが V7.0.1 パッチ・レベル以上であることを確認し、またバグの疑いがある場合には、公開されている Notes/Domino fix listLotus Support Knowledgebase をチェックしてください。

Web サービス・クライアントがタイムアウトしても、Web サービスは実行を継続している可能性があります

コンパイルに長い時間を要する Web サービス・メソッドを Web サービス・クライアントがコールする場合には、Web サービスがその処理を終了する前にクライアント・コードがタイムアウトしてしまう可能性があります (Web サービス・クライアントのタイムアウトのデフォルト値は 60 秒が一般的です)。

たとえレスポンスを待っているクライアントがタイムアウトしてしまっても、Web サービスはその処理が終了するまで、あるいは Domino Server 文書で設定されるエージェント・タイムアウト・リミットまでリクエストの処理を続けるので、注意が必要です。大きなファイルをアップロードする場合、あるいは複雑なデータベース・トランザクションの場合には、Web サービス・クライアントはタイムアウト・メッセージを受け取るかもしれず、また実際にはアップロードまたはプロセスが行われていても (そして数分後には終了するとしても)、それは行われなかったと考えるかもしれません。

これに関連した注意として、Lotus Domino V7 での新しいエージェント・プロファイリング手法を使うことによって、Web サービスのさまざまな部分を実行するために必要な時間のログを生成できることを忘れないでください。エージェントや Web サービスのプロファイリングを有効にし、使用するための方法の詳細に関しては、Lotus Domino Designer Help を参照してください。

複合データ型として使われる、LotusScript クラスの public プロパティーがアルファベット順であることを確認する

この問題は今後のバージョンの Lotus Domino では解決されるかもしれませんが、リリース 7.0.1 の時点では、LotusScript 複合データ型クラスの public プロパティーがアルファベット順でないと、問題が起こる可能性があります。例えば、次のコードは動作します。


リスト 20. アルファベット順に並んだ LotusScript 複合データ型プロパティー (適切)
                
				
Class Book
	Public author As String
	Public booktype As String
	Public title As String
End Class

しかし、次のコードでは問題が起きる可能性があります。


リスト21. アルファベット順に並んでいない LotusScript 複合データ型プロパティー (不適切)
                
				
Class Book
	Public title As String
	Public author As String
	Public booktype As String
End Class

この問題による症状としては、パラメーターとして送信される、あるいはレスポンスとして返される複合データ・オブジェクトに、一部の要素が欠けてしまうことです。これは解決するのがやっかいな問題ですが、多くの場合は public プロパティーをアルファベット順に並べることで解決できます。

ただし、単純にソースコードの中でプロパティーを並べ替えるだけでは不十分なことに注意してください。これは、(たとえプロパティーの順序が変更されても) プロパティーのリストが同じである限り WSDL は再生成されないためです。そこで、次のようにする必要があります。

  1. プロパティーを並べ替える
  2. 新しい、偽のプロパティーを追加する
  3. Web サービスを保存して閉じる
  4. 再度 Web サービスを開く
  5. 偽のプロパティーを削除する
  6. Web サービスを保存して閉じる

これがどの Web サービス・クライアントに限定された問題なのか、私達にもわかっていませんが、Apache Axis と Apache SOAP の両方を使用する際に起きることはわかっています。

Web サービスから受信した大きなストリング (32 KB 以上) を NotesDocument のプレーン・テキスト・フィールドに書き込む際には注意する

複合データ型のパラメーターあるいは要素を使い、その値を NotesDocument に書き込む Web サービスは一般的です。これを行う場合には、1 つの文書に対する Notes のプレーン・テキスト・フィールドが 64 KB (約 32,000 文字) に制限されていることに注意してください。これよりも大きな値をテキスト・フィールドに書き込もうとすると、予期せぬエラーを受信する羽目になります。

NotesDocument のテキスト・フィールドに書き込むデータが 64 KB よりも大きくなる可能性がある場合は、そのデータを Rich Text フィールドに書き込んだ方が無難です。

LotusScript で base64 エンコーディング/デコーディングを使用する場合は、LS2J と Java を使うことを検討する

Web サービスの中で、20 KB よりも大きいファイルに対して base64 エンコーディングまたはデコーディング・オペレーションを行う場合には、XSD_BASE64BINARY クラスの中にあるネイティブの LotusScript エンコーディング/デコーディングではなく、Java を使った方が得策かもしれません。大きなデータ・ストリングを構文解析する場合、LotusScript は比較的遅いのですが、Java は非常に高速です。

この機能を LS2J と Java を使って提供する方法については、Web Services Bookstore データベースの例を見てください (ダウンロード・セクションにあります)。BookDownloadUpload Web サービスの BookInfoAndFile クラスの getFile メソッドと setFile メソッドは、Base64 LS2J という LS2J スクリプト・ライブラリーをコールします (このライブラリーは Base64Java スクリプト・ライブラリーのカスタム Java クラスを使っています)。

約 150 KB のファイルを使ってテストしたところ、LS2J ルーチンを使って行った base64 デコーディングは、ネイティブの LS2J ルーチンを使った場合よりも約 100 倍高速でした (私達のワークステーションでは、1 秒か 2 秒に対して約 2 分という違いでした)。


まとめ

Lotus Domino V7.0 での Web サービスに関するこの 3 回の連載では、Lotus Domino を使った Web サービスを理解し、使いこなすために、基本的な概念から複雑なサービスの作成に至るまでの全プロセスを解説しました。そして、単純なデータ型や配列、複合データ型、列挙、ファイル添付、そして LotusScript Web サービスでのカスタム・フォールトなどの使い方を解説し、そうした概念それぞれに関する実用的なサンプル・コードと、すぐに使用できるサンプル・データベースなども紹介しました。サンプル・データベースには、LotusScript での Web サービスに対応する Java Web サービスも含まれているため、それらを見れば LotusScript メソッドがどのように Java にマッピングされるかも理解できるはずです。さらに、さまざまなフリー・ツールを利用して Web サービスをテストする方法についても解説しました。またダウンロードできるサンプル・データベースには、Lotus Notes V7.0 クライアントから直接 Web サービスをコールするためのエージェントが、いくつか含まれています。

こうした強力な手法を自在に使いこなせば、Domino データベースをエンタープライズ SOA アーキテクチャーへ積極的に取り込むことができます。それによって、機能的な面でも設計的な面でも、アプリケーションや組織全体にとって大きな可能性が生まれます。これは Lotus Notes/Domino が前進する方向の単なる 1 つに過ぎず、また Lotus Notes/Domino が重要で生産的なアプリケーション開発のプラットフォームであり続ける理由の1 つでしかありません。



ダウンロード

内容ファイル名サイズダウンロード形式
Sample database for articleWSBookstore.nsf1.82 MBHTTP

ダウンロード形式について


参考文献

学ぶために

製品や技術を入手するために

  • LotusScript から Web サービスを呼び出す最新の MSSOAP ツールキットをダウンロードしてください。

  • Lotus Notes Java エージェントで使用する Apache Axis スタブ・ファイルを生成するための、Stubby データベースをダウンロードしてください。

議論するために

  • developerWorks blogs を訪れ、developerWorks のコミュニティーに加わってください。

著者について

Julian Robichaux は、ソフトウェア開発者であると同時に、IBM Lotus Notes と Java 開発を専門とするプロのプログラマーで、開発、アーキテクチャー、トレーニングが関わる大小のプロジェクトに契約ベースで参加しています。余暇は、個人の Web サイト/ブログ (http://www.nsftools.com) に費やしています。彼の家族は、どうして彼がどこに行くにもラップトップと一緒なのか理解できませんが、それは本人にしても同じことです。

不正使用の報告のヘルプ

不正使用の報告

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


不正使用の報告のヘルプ

不正使用の報告

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


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=Lotus, SOA and Web services
ArticleID=276514
ArticleTitle=IBM Lotus Domino 7 での実用的 Web サービス: 複雑な Web サービスを作成する
publish-date=11212006
author1-email=jdw@nsftools.com
author1-email-cc=

タグ

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

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

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

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

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