この記事では、Lotus Connectors LotusScript Extension (LCLSX) での添付ファイルの使用方法について解説します。LCLSX ではどのように添付ファイルを扱うのかを示し、サンプル・アプリケーションを用いて添付ファイルの処理方法を説明します。

Andre Guirard (Andre_Guirard@us.ibm.com), EI Product Developer, EMC

Andre Guirard is a member of the development team for the Notes Client and Domino Designer. A long-time Notes developer, Andre now focuses on developer enablement. He often speaks at Lotusphere and other IBM conferences, and his articles have previously appeared on developerWorks: Lotus (LDD), as well as in The View magazine and elsewhere. In his free time, he is the Labor Pool for his wife's gardening projects.


developerWorks 貢献著者レベル

2005年 4月 05日

はじめに

Lotus Connectors LotusScript Extension (LCLSX) を使用すると、Notes データベースとリレーショナル・データベース間で単純なフィールドを簡単に同期することができます。テキスト、日付、数値フィールドであれば、何の問題もありません。また、リッチテキストフィールドをプレーンテキストとして保存したり、リレーショナル BLOB フィールドに保存することもできます (ただし、リッチテキストフィールドのバイナリー・エンコーディングは、Lotus Notes/Domino を除いて使用できません)。

しかし、添付ファイルの取り扱いには少し複雑な部分があります。Notes ネイティブクラスも LCLSX も、添付ファイル内のデータへの直接アクセスはサポートしていません。Lotus Notes から添付ファイルを抽出する唯一の方法は切り離してディスクに保存することで、添付ファイルを作成する唯一の方法はディスク・ファイルから作成することです。しかし、LCLSX を使用すると、添付ファイルの保存と添付を自動化することができ、Notes データを扱うときと同様に、添付ファイルの処理も簡単になります。

この記事では、リレーショナル・データベースとの間で Notes 添付ファイルをコピーするサンプル・アプリケーションを手順を追って説明します。この記事は、LCLSX の使用経験と用語の知識がある方を対象に書かれています。LCLSX を初めて使用する場合は、IBM Redbook『Implementing IBM Lotus Enterprise Integrator 6』を参照してください。この本には LCLSX の章があり、豊富な例を用いてこの技術の基礎が解説されています。


LCLSX での添付ファイルに関する一般的な考え方

LCLSX の Notes Connector には、添付ファイルの操作に使用される次のプロパティが含まれています。

  • LoadFile は Boolean 型のプロパティです。True に設定されると、Selec メソッドから返される結果セットに、FILE という名前の特殊フィールドを追加します。また、Notes 文書に Fetch を実行するときは、常に文書内のすべての添付ファイルがローカル・ファイル・ディレクトリーにコピーされ、それらのファイル名が FILE フィールドに複数値のリストとして格納されます。Notes 文書を更新または挿入するときは、FILE フィールドに登録されているすべてのファイルが Notes 文書に添付されます。
  • FilePath は文字列値で、Notes 文書を取得するときに添付ファイルを保存するディレクトリーのファイルパスを定義します (LoadFile が True の場合)。空のままにしておくと、現在のディレクトリーが使用されます。このプロパティは空にしないでください。通常、現在のディレクトリーは Notes プログラム・ディレクトリーになり、このディレクトリーには数多くのファイルが含まれています。もし、保存する添付ファイルと同じ名前のファイルがあれば、上書きされてしまいます。
  • CopyFile は Boolean 型のプロパティです。True に設定されると、Select メソッドによって返される結果セットのフィールドリストに、LCXFILE という名前の特殊フィールドを追加します。このフィールドリスト (fieldlist) によって他の Notes 文書を挿入または更新する場合は、すべての添付ファイルが新規文書にコピーされます。

この記事では、最初の 2 つのプロパティを使用しました。CopyFile は、Lotus Notes とリレーショナル・データベース間ではなく、2 つの Notes データベース間で添付ファイルを転送するときにのみ有効です。

これで、Notes 添付ファイルのデータをファイルに取り出す方法が得られました。次のステップとして、リレーショナル・データベースのバイナリー・フィールドに保存されているファイルの内容を取得します。これを行うには、バイナリー・ファイルのデータを LCField オブジェクトに取り込む必要があります。このときに使用するツールが File Connector です。File Connector は、ファイルシステムにあるデータに、リレーショナル・テーブルの場合と同様の方法でアクセスします。各ファイルは結果セットの 1 行として表され、使用しているオペレーティング・システムにかかわらず、各ディレクトリー・テーブルには同じ 4 つの列が含まれます。

  • Filename は、フルパスを含まないファイル名です。
  • Contents はファイル内のデータです。データは、Connector の Binary プロパティの設定に応じて、バイナリー形式またはテキスト形式のいずれかになります。この記事の目的として、バイナリー形式を使用し、添付ファイルの内容が正確に保持されるようにします。
  • Timestamp は、ファイルが最後に変更された日時を示します。
  • Size は、ファイルのサイズをバイト数で示します。

Lotus Notes からのエクスポート・プロセスとは、Notes Connector を使用して Notes 文書からデータを Fetch (取得) することです。このとき、各添付ファイルごとにファイルが自動的に保存されます。File Connector を使用してこれらのファイルをメモリに読み込み、任意のリレーショナル Connector を使用してファイルのデータをバイナリー列に格納します。他の方法として、レコードを File Connector に挿入することもできます。この場合は、ファイルが作成されます。

インポートまたはエクスポートにかかわらず、コネクションをセットアップするステートメントはほぼ同じです。このエクスポートのサンプルで Notes Connector のセットアップに使用したステートメントは次のとおりです (読み取りまたは書き込みにかかわらず同じです)。

	Dim lcconNotes As New LCConnection("notes")
	lcconNotes.server = db.server
	lcconNotes.database = db.filepath
	lcconNotes.metadata = "Villain"
	lcconNotes.FilePath = containing_folder + "\" + foldername
	lcconNotes.LoadFile = True

ディレクトリーの区切り記号として \ が使用されているので、これは Windows オペレーティング・システムで使用することが前提となります。次に、File Connector を以下のようにセットアップします。

	Dim lcconFiles As New LCConnection("file")
	lcconFiles.Database = containing_folder
	lcconFiles.Metadata = foldername
	lcconFiles.Binary = True

最後のステートメントは、ファイル・データがバイナリーであることを指定します。つまり、File Connector はバイトを文字として変換しません。サンプル・コードでは、カスタム・クラスを使用して、実行の終了時に自動的に削除される一時ディレクトリーを作成します。


サンプル・アプリケーション

ここで説明するコードを含むサンプルの Notes データベースをダウンロードできます。アプリケーションの名前は「Dick Tracy Crime Files」(ディック・トレーシーの犯罪ファイル) です。有名な刑事ディック・トレーシーは、長い間 Lotus 製品のファンです。彼は既知の犯罪者を追跡するためにこのデータベースを作成しました。犯人の顔写真は、JPEG 添付ファイルとして保存されています。この Notes データを JPEG がバイナリー列に格納されているリレーショナル・データベースと統合する必要があります。

Notes の Villain (犯人) 文書には、フィールド ID が含まれています。これは、レコードを他のリレーショナル・テーブルと関連付けるために使用される固有のキーです。更新が必要なデータを含むテーブルは、次の 3 つの列を持っています。

  • VillainID 列。Lotus Notes から ID フィールドをコピーします。犯人は複数の顔写真を持つことがあるので、この列には固有の値は含まれません。
  • Filename 列。JPEG ファイルのオリジナルの名前が含まれます。VillainID と Filename を組み合わせたものは、固有であると考えられます。
  • Filedata 列。バイナリー・ファイルの内容です。

このサンプル・スクリプトには、他の Notes フィールドと他のテーブル間の同期も含まれていますが、記事では添付ファイルだけを取り上げることにします。

サンプル・スクリプトを実行するためのセットアップ

スクリプトは Notes Client から実行できます。もちろん、スクリプトを実行するためには、エクスポート先とインポート元となるリレーショナル・データベースが必要です。どのデータベースでもかまいません。Microsoft Access でも動作します。必要なテーブルが存在しない場合、サンプル・スクリプトはそのテーブルを自動的に作成します。このため、リレーショナル・データベースへのログインには、これを行うアクセス権が必要です。

これまでに説明したように、スクリプトは Domino Server 上の DECS (または LEI) Administrator データベース (decsadm.nsf) から接続情報を読み込みます。このデータベースは、ローカルに置くこともできます。DECS または LEI を実行する必要はありませんが、decsadm.nsf データベースが存在しなければなりません。DECS Administrator テンプレート (decsadm.ntf) を使用して、このデータベースを作成できます。また、スクリプトライブラリ内に接続情報をハードコードすることも可能です。いずれの場合でも、このスクリプトライブラリを編集できます。スクリプトライブラリの名前は「Customize Connections」です。(Options) セクションに、いくつかの Const ステートメントがあります。次のパラメータの値を調整することにより、接続情報を検索する場所をスクリプトに知らせます。

  • YOUR_CONNECTION_DOC には、DECS Administrator データベースでスクリプトが検索するコネクション文書の名前が含まれます。
  • VILLAINS_MAIN、VILLAINS_CRIMES、および VILLAINS_ATTACHMENTS には、データのエクスポート先の 3 つのテーブルの名前が含まれます。
  • YOUR_DECS_SERVER には、DECS Administrator データベースが置かれているサーバーの名前が含まれます。ローカルの場合は、空のままにしておきます。

リレーショナル・データベースのタイプ、名前、ID、およびパスワードをハードコードしたい場合は、このスクリプトの各モジュールに示されているカスタマイズ方法の説明を参照してください

このライブラリをカスタマイズした後は、YOUR_CONNECTION_DOC に入力したコネクション文書を作成します。これで準備が整いました。

サンプル・スクリプトの実行

Notes Client でデータベースを開き、[Villains \ by ID] ビューを開きます。このビューには 4 つのサンプル文書があります。[アクション] メニューには番号付きのエージェントがあり、この番号順に実行します。

1: Create/Clear Tables
このエージェントは、LCACTION_TRUNCATE 引数とともに Action メソッドを使用し、3 つのリレーショナル・テーブルにあるすべてのデータを削除します。テーブルが存在しない場合、スクリプトはそのテーブルを作成します。スクリプトを見ると LCLSX でテーブルを作成する方法がわかりますが、この記事の範囲外の内容なので、ここでは詳しくは説明しません。

2: Export Villains to RDB
このエージェントは、前述のエクスポート・プロセスを実装します。文書は 4 つだけなので、このスクリプトではパフォーマンスは大きな問題にはなりません。しかし、パフォーマンスが問題となるアプリケーションについても考慮し、ベストプラクティスに従って、コピーされるフィールド間に最初にリレーションシップを確立しました。これにより、メインのプログラム・ループ内のフィールド間でデータを移動することなく、コピーを自動的に実行できます。

これを行うには、同じフィールド・オブジェクトへの参照を含むフィールドリストを作成します。LCField は個別のオブジェクトなので、複数のフィールドリストから参照できます。それぞれのフィールドリストは、異なる名前で識別されます。図 1 において、四角形はフィールドリスト要素を表し、楕円は LCField オブジェクトを表します。これらを接続する線は、どのフィールドリスト要素がどの LCField オブジェクトを参照しているかを示します。

図 1. フィールドリスト
イメージ

このような種類のプログラミングを行うときは、常に図を作成することをお勧めします。図は、このように整ったものばかりではなく、もっと複雑になることもあります。このようにフィールドリストをセットアップすることにより、Notes データベースから文書を読み込むことができ、2 つの他のテーブルに書き込むデータは、リレーショナル・データベースに挿入するフィールドリストにすでに存在します。Notes レコードを読み込むときに、ファイルが自動的に作成されます。これらのファイルは、File Connector で読むことができます。そして、リレーショナル・データベースの添付ファイルテーブルに挿入するフィールドリストにデータはすでに存在しています。

リンクされたこれらのフィールドリストを作成するコードは次のとおりです。

Call lcconNotes.Select(Nothing, 1, flNotes) ' select all docs, init flNotes
Call lcconFiles.Select(Nothing, 1, flFiles) ' init flFiles (no files yet)
Call flDest.MapName(flNotes, "ID,Name,Location,Body", "VillainID,Name,Hideout,Comments")
Set fldID = flDest.Lookup("VillainID")
Call flDestAtt.MapName(flFiles, "Filename,Contents", "Filename,Filedata")
Call flDestAtt.IncludeField(3, fldID, "VillainID")
Call flCrimes.MapName(flNotes, "ID,Crimes", "VillainID,Crime")
Set fldCrimes = flNotes.Lookup("Crimes")
/pre>

2 つの Select ステートメントは、2 つのソース・フィールドリスト用のフィールド・オブジェクトを作成します。すべての Notes 文書を読み込みたいので、最初の Select は 2 つの目的で使用されます。しかし、一時ディレクトリーにはまだファイルが存在しないので、File Connector の Select はフィールドリストを初期化する目的でのみ使用されます。

それに続くステートメントは、同じフィールドへの新しい参照を作成し、これらを他のフィールドリストに挿入します。その後に続くエクスポート・プログラムのメイン・ループは、たいへんシンプルです。

Do While lcconNotes.Fetch(flNotes) > 0
    ' Fetch はすべての添付ファイルを       
    ' 一時ディレクトリーに保存します。       
    Call lcconDest.Insert(flDest) ' メインの villain レコードを作成します。       
    Call lcconDestCrimes.Insert(flCrimes) ' 複数の犯罪の行を      
    ' 1 つのオペレーションに含めます。       
    Call lcconFiles.Select(Nothing, 1, Nothing) ' 一時ディレクトリーに       
    ' どのファイルがあるか確認します。       
    Do While lcconFiles.Fetch(flFiles)       
    Call lcconDestAtt.Insert(flDestAtt) ' 1 つのファイルを添付ファイル       
    ' テーブルに挿入します。       
    Loop       
    Call lcconFiles.Action(LCACTION_TRUNCATE) ' 添付ファイルを       
    ' 削除します。
Loop

フィールドリスト flNotes への Fetch も、一時ディレクトリーにファイルを作成します。スクリプトは、これらのファイルのリストを得るために File Connector から選択し、その内容を読み込みます。Select ステートメントの 3 番目の引数が Nothing であることに注目してください。通常は、結果セットのフィールドを格納するために空のフィールドリストを提供しますが、結果の取得が必要なフィールドリストはすでに持っているため、別のフィールドリストを作成する必要はありません。実際に、既存のフィールドリストは出力フィールドリストへリンクされているので、新規のものよりも価値があります。

このプログラムで、考慮すべき点をいくつか挙げます。

  • 目的のデータベースを指す 3 つの LCConnection オブジェクトを使用します。各テーブルごとに 1 つのオブジェクトが対応します。メイン・テーブルと添付ファイル・テーブル用の Connector はデータベースに直接接続されますが、犯罪テーブルへのコネクションは Collapse/Expand Metaconnector を介して接続されます。この Metaconnector は、Notes の複数値フィールドと 1 対多のリレーショナル・テーブル内の複数行との間で、自動的に変換を行います。これについては、この記事の範囲外の内容ですが、コードを参照することで、どのような方法で行われるかがわかります。
  • Notes のフィールドリストは 1 つの FILE フィールドを持っています。このフィールドには、保存されたファイルのフルパスのリストが含まれています。しかし、エクスポート時には、このフィールドを使用する必要はありません。スクリプトでは、File Connector を使用してファイル名と内容をディスクから直接取得するので、この方法で同じ情報を得ることができます。ディレクトリーに他のファイルが含まれている場合は別の処理になりますが、その場合は新しい一時ディレクトリーを作成することになるので、この点について心配はありません。
  • Notes 文書の取得時に添付ファイルを自動的にディスクにコピーできるので、作業後に添付ファイルを自動的に削除する機能はありません。ループの最後で、Action メソッドは、ディレクトリーの内容を保持するテーブルを切り捨てることにより、一時ディレクトリーからすべてのファイルを消去します。
  • Notes 文書の Body リッチテキストフィールドは、リレーショナル・データベースのバイナリー BLOB フィールドにマッピングされています。これによって、リッチテキストフィールドの未加工のバイナリー・イメージが BLOB フィールドにコピーされます。このデータは、Lotus Notes にインポートして戻さない限り使用できない独自形式です。フォームの編集時に添付ファイルのアイコンがリッチテキストフィールド内に表示されても、添付ファイルはリッチテキストとは別に保管されます。つまり、リッチテキストをコピーしても、添付ファイルはコピーされません。しかし、この方法により、リッチテキストフィールドに表示される埋め込みイメージと他のデータのバックアップコピーを作成できます。バックアップは、後で Lotus Notes にリストアすることができます。
  • 内部ループは、一時ディレクトリーで見つかったすべての添付ファイルを取得し、それぞれを添付ファイル・リレーショナル・テーブルに挿入します。このとき、VillainID とファイル名の組み合わせを使用して、レコードに固有の識別子を付与します。内部的に、Notes は一意でない名前を変更することによって、同じ文書内で添付ファイル名が重複することを防止します。したがって、重複キーは問題にはなりません。
  • メイン・ループの実行時に、DebugStr というカスタム関数を使用して、ディスクに書き込むデータの説明用の文字列を作成します。レコード・セットを書き込むときに、そのレコードに関する情報を示すメッセージボックスが表示されます。前のコードでは、出力をデバッグする行が省略されているので、データを移動する機能だけを見ることができます。

3. Import from RDB
次のエージェントは、前のエージェントとは逆の処理を行います。このエージェントは、リレーショナル・データベース内のデータからの添付ファイルを持つ Notes 文書を新規作成します。ソースのデータ・レコードを削除したくないため、2 つ目の Notes フォームを作成しました (Villain フォームに似ていますがフォーム名は「Bad Guy」です)。インポートスクリプトは、この文書タイプを作成します。

リレーショナル・データベース内のデータからファイルを作成する必要があるので、メインの Villains リレーショナル・テーブルからのキーを使用して、添付ファイル・リレーショナル・テーブルから選択します。このデータを使用し、File Connector に挿入することによってディスク上にファイルを作成します。次に、Notes Connector に挿入します。これによって、ディスクからファイルを取得し、Notes 添付ファイルが自動的に作成されます。

しかし、Notes Connector の LoadFile プロパティを使用して読み取る場合と書き込む場合では、1 つの重要な違いがあります。読み取る場合は、Notes フィールドリスト内の FILE フィールドを無視して、どのファイルが作成されるのかを確認できます。しかし、書き込む場合は、FILE フィールドを使用して、添付したい各ファイルの完全なファイルパスを Lotus Notes に通知しなければなりません。これは、目的のディレクトリーにあるすべてのファイルを選択するというような単純なことではありません。

FILE フィールドは特殊なフィールドです。特殊なのは名前だけでなく、このフィールドには、Notes Connector に対して特別の扱いを求める仮想フィールド・コードが設定されています。このフィールド・コードによって、添付ファイルをリストする機能を持ったフィールドと、名前が単に FILE である通常フィールドを識別できます。特殊な名前を持ち、Notes Connector によって使用されるフィールドはいくつかありますが、これらはすべて仮想フラグを持っています。

メモ:この仮想フィールド・フラグは、DECS および LEI の Virtual Fields アクティビティとは混同しないでください。このアクティビティは、リレーショナル・データベースからリアルタイムの情報を取得します。同じような名前を持っていますが、概念は大きく異なっています。



メイン・ループに入る前に、インポート・スクリプトは、リンクされたフィールドリストのセットを生成します。これは、特殊な FILE フィールドも含め、前のスクリプトとたいへんよく似ています。(これらのフィールド間の関係を図解することは、読者への課題とします。)前述のように、テーブルに一致するフィールドリストを作成する簡単な方法は、Select を使用してテーブルの説明を取得することです。複数値フィールドや仮想フィールドなどの特殊フィールドがリストに含まれる場合は、特にこの方法が使用されます。しかし、説明に適した例を作成する場合は、簡単な方法を用いなくてもよいでしょう。次に示すのは、独自の FILE 仮想フィールドを初めから作成するコードです。

Set fldFiles = flNotes.Append("FILE", LCTYPE_BINARY)

フィールドはバイナリー型ですが、BLOB フィールドではありません。バイナリー・フィールドは、リッチテキストフィールドや複数値フィールドなど、特殊な Notes フィールドの値を格納するために使用されます。

Call fldFiles.SetFormatStream( , , LCSTREAMFMT_TEXT_LIST)

バイナリー・フィールド型である、複数値の Notes テキストフィールドを割り当てました。

Call fldFiles.SetVirtualCode(lcconNotes.GetPropertyInt(LCTOKEN_CONNECTOR_CODE))

SetVirtualCode 関数には、どの Connector またはコネクションがこのフィールドを特別に扱えるのかを示す引数が必要です。特殊とみなすフィールド名は Connector ごとに異なるので、Lotus Notes に対しては特殊フィールドとし、その他の Connector に対しては特殊フィールドとしないよう指定することが可能です。これは、異なるバックエンドが持つ固有の機能にアクセスするための 1 つの方法です。ここで割り当てたフラグにより、このフィールドに特殊な注意を払うよう Lotus Notes に通知されます。

各 Notes コネクションの Connector コードのプロパティは、同じ数値の値を返します。しかし、Connection コードは 1 つの LCConnection オブジェクトに対して一意です。Connector ではなくコネクションに属する仮想コードを設定することにより、1 つの Notes コネクションを使用して、Notes 文書から名前のリストをロードできます (このコネクションは、FILE を単なる 1 つの複数値フィールドとして扱います)。しかし、2 番目のコネクションに関連するフィールドリストにこのフィールドをリンクすると、このコネクションは FILE フィールドを特殊フィールドとして扱い、これらのファイルをディスク上で検索します。FILE フィールドは、添付するファイルのファイル名だけでなく、完全なパスを含む必要があります。

インポート機能のメイン・ループは、リレーショナル・データベースから読み込む各 Villain レコードごとに、この値のリストを生成しなければなりません。コードは、次のとおりです。

Do While lcconVillains.Fetch(flVillains) > 0          
    Call lcconCrimes.Select(flVillains, 1, Nothing) ' Metaconnector を介して読み込むので、          
    ' 多くても 1 つの結果が常にあります。          
    If lcconCrimes.Fetch(flCrimes) = 0 Then         
    fldCrimes.Value = "" ' 犯罪がない場合は、前回の繰り返しから          
    ' 残された値を削除します。          
    End If          
    strFilenames = ""          
    Call lcconAttach.Select(flVillains, 1, Nothing)          
    ' 現在のキーに一致する添付ファイル・リレーショナル・レコードの          
    ' リストをループし、各ファイルを一時ディレクトリーに保存します。          
    Do While lcconAttach.Fetch(flAttach)          
    Call lcconFiles.Insert(flFiles) ' ファイルの内容を          
    ' ディスク・ファイルにコピーします。保存するファイルの           
    ' フルパスを示す、区切り記号付きの文字列を構築します。          
    strFilenames = strFilenames & NEWLINE & dirTemp.fullpath &           
    "\" & fldFilename.Text(0)          
    Loop         
    ' 添付ファイルがある場合は、複数値を含む文字列を作成します。          
    ' 各値は 1 つのファイルのフルパスです。          
    If strFilenames <> "" Then          
    lcstrFilenames.Value = Split(Mid$(strFilenames, 2), NEWLINE)          
    Else          
    Call lcstrFilenames.Clear          
    End If          
    Call fldFiles.SetStream(1, lcstrFilenames) ' FILE 複数値フィールドを          
    ' 添付するファイルのリストに設定します。          
    Call lcconNotes.Insert(flNotes)          
    Call lcconFiles.Action(LCACTION_TRUNCATE) ' 一時的な          
    ' 添付ファイルを削除します。
    Loop

変数 lcstrFilenames は LCStream オブジェクトです。LCStream は、各テキストおよびバイナリー LCField オブジェクトごとのデータを格納するために使用されるオブジェクトです。あまり使用されることはありませんが、Notes 複数値などのバイナリー・フィールドのデータを直接扱うときにたいへん役に立ちます。LCStream クラスは複数値フィールドのテキストを単に代入するだけでなく、フィールドを複数の値に分割することも可能です。しかし、区切り記号としてカンマを使用するため、データの値にカンマが含まれていない場合にのみ機能します。

次の点に注意してください。

  • フィールドリスト flVillains 内の VillainID フィールドは、キー (LCFIELDF_KEY) として設定されます。データをフィールドリストにロードする Fetch オペレーションによってこのフラグは無視されますが、このフラグによって、関連する犯罪と添付ファイル・レコードを得るために Select への選択条件の引数として flVillains を使用できるようになります。
  • 2 つの関連するテーブルから選択するときは、3 番目のパラメータとして Nothing を指定します。すでに結果セットのフィールドセットを持っているので、Select の間にこれを構築する必要はありません。また、既存のフィールドリストは他のフィールドリストとすでにフィールドを共有しているので、新規のものよりは価値が高くなります。
  • dirTemp.fullpath という式は、一時ディレクトリーを作成して処理後に自動的に削除するカスタム・クラスのプロパティを参照します。このクラスは他のスクリプトでも役に立ちます。このプロパティは、一時ディレクトリーのフルパスを返します。
  • 繰り返しになりますが、ディレクトリーの区切り記号として \ を使用しているので、このスクリプトは Windows オペレーティング・システムでのみ機能することに注意してください。
  • FILE フィールドへの代入時に、完全なファイルパスを使用する必要はありません。代わりに、Notes の現在のディレクトリー (Curdir) を一時ディレクトリーとして設定し、ファイル名だけを使用することもできます。しかし、Curdir を設定することは、(1) 同じプロセスで他のスクリプトが並行して実行される可能性があり、(2) これらのスクリプトも Curdir を設定している (または、デフォルト値を持つと仮定している)、という 2 つの理由から、あまり安全な方法ではありません。
  • 残念ながら、Notes Connector の FilePath プロパティを設定しても、FILE の値でパスが指定されていない場合は、そのディレクトリーでファイルを検索しません。
  • このスクリプトでも Collapse/Expand Metaconnector を使用しています。この場合は、複数のリレーショナル行から 1 つの Notes 複数値フィールド (Crime) への変換に使用しています。

実際のアプリケーションにおける同期

これまでに説明したスクリプトは、かなりシンプルです。実際には、データベース間で単にデータをダンプするよりも、より複雑な処理がアプリケーションで行われています。さらに一般的なのは、異なるデータソース間で情報を同期することです。

もちろん、データの移動が 1 方向の場合は、ターゲットのすべてのデータを削除し、ソースのすべてのデータをコピーすることによって同期する方法も考えられます。これは、無精なプログラマーの手法として知られています。アプリケーションによってはこれで機能するかもしれませんが、良くない方法であることを示す要因がいくつかあります。

  • 種類にかかわらず、多くのデータベースには、レコードが追加、削除、または変更されたときに起動される、カスタムのイベント・コードがあります。1 つのレコードを削除し、削除したものと同じ内容の新規レコードを追加すると、不要な処理が発生し、予期せぬ結果が生じる可能性があります。
  • ターゲットが Lotus Notes の場合、すべての Note 文書を削除して再作成することには、数々の欠点があります。
    • 今日作成された文書リンクが、明日機能するとは限りません。
    • 削除によって削除スタブが残されます。これは、データベースのサイズを増加させるとともに、複製とビューの索引更新の時間を増加させます。また、一般的にパフォーマンスを低下させます。特に、アクティブな文書よりも 40 倍の削除文書があるときは、パフォーマンスの低下が顕著です。
    • 未読マークが失われます。
    • Domino Server にも、API アドインや文書の新規作成または変更によって起動されるエージェントなど、イベントベースの処理があります。
  • 他の種類のデータベースでは、データの入れ替えにともなうパフォーマンスの低下が発生することがあります。

これらの課題への対応を補助するために、サンプル・データベースには、2 つの LCConnections 間でキーに基づく 1 方向のシンプルな同期を行うサンプル・エージェントが含まれています。[5. Replicate Pirates] エージェントには、再利用可能な複製エンジンが含まれています。このエンジンは、双方の結果セットから一度にレコードを 1 つずつ読み込み、キーとデータ値を比較してレコード間に違いがあるかどうかを判断します。違いがある場合は、それが挿入、更新、削除のいずれであるかを示します。そして、必要に応じて次のレコードが一方または双方の結果セットから読み込まれます。等しくソートした 2 つの結果セットをこのエンジンに提供する方法については、読者の方にお任せします。Connector の組み合わせによっては、Order Metaconnector を使用する必要があるかもしれません。これを行うことによって、プロセスを自動化できます (少なくとも、単純なフィールド型の場合は自動化されます)。

この手法は、必要とする任意のファイル添付の操作と組み合わせることができます。しかし、LCStream オブジェクトを使用して 2 つの添付ファイルのバイナリー・データを比較し、同じであるかどうかを判断するよりも、タイムスタンプを比較する方がずっと早いでしょう。


まとめ

この記事では、LCLSX で添付ファイルを操作する方法を解説しました。最初に、LCLSX がどのように添付ファイルを扱うのかについて簡単に触れ、その後でサンプル・アプリケーションを紹介し、添付ファイルの処理方法を詳しく見ていきました。最後に、実際のアプリケーションで同期を行う手法についても検討しました。

この記事が、読者の皆さまのお役に立つことを望んでいます。サンプルをダウンロードし、必要に応じて改変し、使用することもできます。ぜひ、ご利用ください。

参考文献

コメント

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
ArticleID=340947
ArticleTitle=LCLSX での添付ファイルの操作
publish-date=04052005