SharePoint のタイマーサービス (WSS Timer サービス) を活用する

環境 :
Office SharePoint Server (MOSS) 2007
Visual Studio 2005

こんにちは。

今日は、開発者にとっての SharePoint のタイマーの活用術について記載しましょう。

SharePoint では、専用のタイマーのサービス (Windows サービス) が動作しており、さまざまな種類のタイマーを利用することができます。今回はそうしたいくつかの種類のジョブスケジュールの中から、SharePoint のインデクス検索 (SharePoint サイトや共有フォルダなどのクロール) 機能を活用した、Search and Process (検索と処理) のジョブを使用するサンプルを紹介しましょう。

まず基本的な仕組みですが、タイマーの処理は、SQL Server のコンテンツデータベース (通常は、WSS_Content_[id] という名前のデータベースです) の中の dbo.ScheduledWorkItems に保存され、この中に保存されたジョブがタイマーのサービス (OWSTIMER.EXE) により処理されていきます。
ここで1つだけ注意点 (と申しますか、すみません、Known Issue 的なものです) があります。osql や SQL Server Management Studio (もしくは SQL Server Management Studio Express) でデータベースをのぞいていただくとわかりますが、このテーブルには Created と DeliveryDate という 2 つの datetime 型の列が存在していて、主に、DeliveryDate の値と Type (ジョブの種類の入った Guid 型の列) をみて実行すべき処理を判断していますが (厳密には、他に InternalState などもみています)、実は、今日ご紹介する方法で実装すると、Created は UTC の時間が設定されるのに対し、DeliveryDate はローカルの時間が設定されてしまいます。よって、この DeliveryDate を UTC に変更しないと、正しい時間に処理がおこなわれないことになります。
この Issue については、当面、以下のような方法でプログラムをおこなうなどして回避する必要があります。(もうしわけありません。)

では、簡単なサンプルプログラムを作成してみましょう。このタイマースケジュールを使って、「10 分後に Contoso というキーワードで検索をおこない、検索結果の1件1件について、データとしてリストに登録する」 というサンプルを作成してみます。

サンプルを作成する前に、「Contoso」というキーワードで検索がヒットするように Word などの文書を作成しておき、
共有サービス (通常は SharedServices1 です) の管理画面で[検索の設定] リンクをクリックして、表示される画面で [コンテンツソースのクロールのスケジュール] のリンクをクリックし、増分クロールなどクロールを実施しておきましょう。(登録されているドキュメント数によっては、クロールに時間がかかります。)
クロールが完了し、「Contoso」で検索できるようになれば準備OKです。

では実装ですが、まず、検索結果の各アイテムで処理するロジックを作成します (GAC に登録します)。
Visual Studio で、クラスライブラリのプロジェクトを作成し、[参照の追加] で、以下の dll の参照を追加します。

%programfiles%common filesmicrosoft sharedweb server extensions12isapiMicrosoft.SharePoint.dll
%programfiles%common filesmicrosoft sharedweb server extensions12isapiMicrosoft.Office.Policy.dll
%programfiles%common filesmicrosoft sharedweb server extensions12isapiMicrosoft.Office.Server.dll
%programfiles%common filesmicrosoft sharedweb server extensions12isapiMicrosoft.Office.Server.Serach.dll

また、名前空間として、以下を追加しておきます。

using Microsoft.SharePoint;
using Microsoft.Office.RecordsManagement.SearchAndProcess;
using Microsoft.Office.Server;
using Microsoft.Office.Server.Search;
using Microsoft.Office.Server.Search.Administration;

各検索アイテムごとの処理ですが、Microsoft.Office.RecordsManagement.SearchAndProcess.IProcess を実装し、このインタフェースの ProcessItem メンバだけを実装すれば OK です。今回は、検索結果のアイテムの名前を所定のリストの中に挿入するという簡単なサンプルにしましょう。

public class Class1 : IProcess
{
    public bool ProcessItem(Microsoft.SharePoint.SPListItem item, string[] rgstrOtherArgs, out string strMessage)
    {
        SPWeb oWeb = new SPSite(@”http://machine01/sites/officedemo”).OpenWeb();
        SPListItem oItem = oWeb.Lists[“test”].Items.Add();
        oItem[“タイトル”] = item.DisplayName;
        oItem.Update();
        strMessage = “test completed !”;
        return true;
    }
}

上記で2番目の引数ですが、ここには、この後作成する要求側のプログラムで自由な引数の配列 (String の配列) を渡すことができるようになっていて、その設定した値がそのまま入ってきます。(今回のサンプルでは特に使いません。)

上記で処理側の実装は終了です。
あとは、プロジェクトのプロパティで [署名] タグを選択し、新しい署名 (snk ファイル) を作成してビルドし、dll を GAC に登録してください。

つぎに処理の要求側を作成します。
今度はコンソールアプリケーションを作成し、上記のクラスライブラリと同じ dll の参照と名前空間の追加をおこなったら、以下の通り処理を作成しましょう。(今回は、http://machine01 の下をすべて検索します。下記の AssemblyName プロパティには、皆さんが登録したクラスライブラリの正式名を GAC の中を確認して記入しておいてください。また、ClassName や UsersToNotify も同様に皆さんのプログラムや環境にあわせて変更しておいてください。)

static void Main(string[] args)
{
    SPWeb searchWeb = (new SPSite(@”http://machine01″)).OpenWeb();

    SearchAndProcessItem spi = new SearchAndProcessItem();
    spi.AssemblyName = “ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e6b2c8aae50e717d”;
    spi.ClassName = “ClassLibrary1.Class1”;
    spi.KeywordQuery = “Contoso”;
    spi.DisplayName = “検索と処理スケジュールのサンプル”;
    spi.MethodArgs = new string[0];
    spi.UsersToNotify = @”DemoUser1@example.jp”;
    spi.SearchApplication = SearchContext.GetContext(searchWeb.Site).Name;
    spi.Add(searchWeb, DateTime.Now.AddMinutes(10).AddHours(-9), searchWeb.ID, 1, true, Guid.Empty, Guid.Empty, 1);

    return;
}

Add メソッドによって先ほど説明した ScheduledWorkItems テーブルに予約されますが、ここで 3 番目の引数に注目してください。
この処理では、10 分後に処理を実施したいのですが、先ほど説明した Issue によって、UTC の時間となるように、ja-JP の 9 時間分をずらしておく必要があります。(こうしないと、いつまでたっても実行されなくなります。)

では、コンパイルして実行してみましょう。

と、その前に、「検索と処理」のジョブが ScheduledWorkItems のアイテムを確認するインターバルですが、デフォルトでは夜間に 1 回実行されるようになっています。ですので、すぐに確認できるように、以下のコマンドで、この処理を 1 分に一回に変更しておきましょう。[SharePoint 3.0 サーバの全体構成の管理] (Central Administration) で、[サーバ構成の管理] 画面を表示し、[タイマジョブの定義] をクリックして [検索と処理] というジョブが毎分になっていたら OK です。

pushd %programfiles%common filesmicrosoft sharedweb server extensions12bin
stsadm -o setsearchandprocessschedule -schedule “Every 1 minutes between 0 and 59”
popd

では、上記のコンソールアプリケーションを実行してみましょう。
すると、約 10 分後に、検索されたアイテムの名前がリストに挿入されているはずです。

タイマーから呼ばれる SharePoint の検索処理のプログラム内部では、KeywordQuery クラスを使った一般的な SharePoint のキーワード検索の処理がおこなわれています。こうした方法を理解しておくと、例えば、レコードセンター (関連掲載は こちら ) への送信を毎回手動で実行するのではなく、対象のファイルの収集と送信を自動化する、といった強力な仕組みを SharePoint の仕組みの 1 つとして実装することができます。

尚、デバッグに際しては、タイマーがアセンブリをキャッシュして使い続けるので (修正のたびにリブートなどが必要になります)、修正前にコンソールアプリなどで動作を確認してから組み込みましょう。

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s