ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Directory Server Enterprise Edition開発者ガイド
11g リリース1 (11.1.1.7.0)
B72440-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

10 一致ルール・プラグインの作成

この章では、Directory Serverでカスタム一致ルールを処理できるようにするプラグインについて説明します。サーバーでは、近似マッチング検索などのLDAP v3の拡張可能な一致をサポートするために、そのような一致ルール・プラグインを必要とします。

この章に示すコードの抜粋は、概念的に単純な大/小文字の完全一致スキームを示しています。ここで、完全一致とは、DirectoryString属性値間のバイト比較です。概念は単純ですが、プラグインのコードは多数の行に渡ります。プラグインでは、索引付け、検索およびソートを使用可能にするラッパー関数に加えていくつかの関数を提供する必要があります。


注意:

独自のプラグインを実装する前に、一致ルール・プラグインがDirectory Serverでどのように使用されるかを理解する必要があります。この章を読んでから、サンプル・プラグイン・コードを確認してください。新しい一致ルール・プラグインを1から作成することは避けてください。


この章の内容は、次のとおりです。

10.1 一致ルール・プラグインの動作

この項では、一致ルール・プラグインの概要およびDirectory Serverでそれらのプラグインがどのように処理されるかを説明します。

10.1.1 一致ルールとは

一致ルールでは、特定の構文を持つ属性値を比較する具体的な方法が定義されます。つまり、一致ルールでは、一致の可能性がある属性の比較方法が定義されます。

各一致ルールは、一意のオブジェクト識別子(OID)文字列によって識別されます。検索を要求するクライアント・アプリケーションでは、検索フィルタに一致ルールOIDを指定できます。OIDにより、2つの属性値の一致をチェックする方法がDirectory Serverに示されます。

実際には、クライアント・アプリケーションでは、指定された値に完全に一致する属性値を持つエントリのみが必要な場合があります。サンプル・プラグインでは、そのような状況に対するソリューションの実装方法を示します。別のクライアントでは、特定のロケールのルールに従ってエントリをソートする場合があります。Directory Serverでは実際に一致ルール・プラグインを使用して、ロケール固有の一致を処理します。

『Oracle Directory Server Enterprise Editionリファレンス』の第14章「Directory Serverの国際化サポート」に、一致ルールのリストが示されています。Directory Serverでは、国際化された検索のルールをサポートしています。デフォルト・スキーマを検索することによっても、リストを表示できます。

$ ldapsearch -h localhost -p 1389 -b cn=schema cn=schema matchingRules

10.1.2 一致ルールの要求

特定の属性に対するカスタム一致ルールを要求するために、クライアント・アプリケーションでは検索フィルタに一致ルールOIDを含めます。LDAP v3ではこれらの検索フィルタを拡張可能な一致フィルタと呼びます。拡張可能な一致フィルタは、次のようなものです。

(cn:2.5.13.5:=Quentin)

このフィルタでは、一致ルール2.5.13.5を使用して、エントリの共通名(CN)でQuentinを検索するようサーバーに指示します。この一致ルールは大/小文字の完全一致です。

大/小文字の完全一致ルール・プラグインOID 2.5.13.5を使用すると、Directory Serverで検索を正確に実行できるようになります。Directory Serverではこの一致ルール・プラグイン内のコードをコールし、検索中に一致をチェックします。また、サーバーはこのコードを使用して、大/小文字完全一致検索を高速化する索引を生成します。索引は、そのような検索中に見つかったエントリをソートする際にも役立ちます。

10.1.3 一致ルール・プラグインの機能

一致ルール・プラグインでは、次の操作を実行するためのコードを提供できます。

  • 拡張可能な一致検索中の一致のチェック

  • ソート制御を使用した拡張可能な一致検索の結果のソート

  • 拡張可能な一致検索を高速化するための索引のメンテナンス(オプション)

これらの機能を使用できるようにするために、プラグインでは、特定の一致ルールを含むリクエストを処理するためにDirectory Serverからコールされる一致および索引付けルーチンを実装します。

プラグインではまた、特定の一致ルールを処理する際にコールするルーチンを指定するファクトリ関数も実装します。その結果、プラグインで複数の一致ルールをサポートできるようになります。ただし、一致ルールを1つのみ実装するプラグインでも、索引付けおよび一致ルーチンを折り返すためにファクトリ関数コードが必要です。したがってプラグインには、最小限の一致ルールを処理する場合であっても、多数のコード行および複数の関数が必要です。

次の表に、一致ルール・プラグインで実装できるすべての関数を示します。

表10-1 一致ルール・プラグインに定義された関数

タイプ パラメータ・ブロック識別子 必須かどうか

フィルタ・ファクトリ

SLAPI_PLUGIN_MR_FILTER_CREATE_FN

必須

フィルタ索引(索引で一致をチェックするために使用)

SLAPI_PLUGIN_MR_FILTER_INDEX_FN

必須ではない

フィルタ一致

SLAPI_PLUGIN_MR_FILTER_MATCH_FN

必須

フィルタ一致リセット

SLAPI_PLUGIN_MR_FILTER_RESET_FN

再使用するためにフィルタをリセットする必要がある場合は必須

フィルタ・オブジェクト・デストラクタ

SLAPI_PLUGIN_DESTROY_FN

メモリーを解放する必要がある場合は必須

インデクサ

SLAPI_PLUGIN_MR_INDEX_FN

必須ではない

インデクサ・ファクトリ

SLAPI_PLUGIN_MR_INDEXER_CREATE_FN

必須ではない

インデクサ・オブジェクト・デストラクタ

SLAPI_PLUGIN_DESTROY_FN

メモリーを解放する必要がある場合は必須

プラグイン初期化関数

使用不可だが、かわりに構成設定で指定される

必須

サーバー停止(クリーンアップ)関数

SLAPI_CLOSE_FN

必須ではない

サーバー起動関数

SLAPI_START_FN

必須ではない


一致ルール・プラグインで使用できるパラメータ・ブロック識別子の詳細は、「プラグインAPIリファレンス」を参照してください。

10.2 一致ルール・プラグインのサンプル

この章に示すサンプル・コード(install-path/examples/matchingrule.cにあります)は、Directory Serverとともにデフォルトでインストールされる機能を模倣しています。このため、独自の一致ルールを実装するようにプラグインを変更する場合を除き、プラグインを構築してロードする必要はありません。サンプルでは、Directory Serverに付属のプラグインのものとは異なるOIDを使用しています。そのため、サンプルをロードするよう選択した場合、サンプル・プラグインが既存のプラグインに干渉することはありません。

10.2.1 一致ルール・プラグインの構成

一致ルール・プラグインのタイプはmatchingruleです。Directory Serverプラグインは、特定のタイプの一致ルール・プラグインに依存する場合があります。Directory Serverでは、プラグインが依存するタイプのプラグインがエラーなしでロードされないかぎり、そのプラグインをロードできません。

Directory Serverへのプラグイン構成エントリのロードの詳細は、「Directory Serverへのライブラリのプラグイン」を参照してください。

10.2.2 一致ルール・プラグインの登録

一致ルール・プラグインにはファクトリ関数が含まれています。ファクトリ関数により、索引付けまたはフィルタ一致ルーチンに対する関数ポインタが動的に提供されます。そのため、ファクトリ関数のみをプラグイン初期化関数の一部として登録します。

索引付けおよび一致の両方を処理するプラグインでは、次の例に示すとおり、ファクトリ関数および説明の両方を登録します。

例10-1 一致ルール・ファクトリ関数の登録(matchingrule.c)

#include "slapi-plugin.h"

static Slapi_PluginDesc plg_desc = {
    "caseExactMatchingRule",           /* Plug-in identifier           */
    "Oracle Corporation (test)",       /* Vendor name                  */
    "11.1.1.3.0",                      /* Plug-in revision number      */
    "Case Exact Matching Rule plug-in" /* Plug-in description          */
};

#ifdef _WIN32
__declspec(dllexport)
#endif
int
plg_init(Slapi_PBlock * pb)
{
    int                       rc;
        
    /* Matching rule factory functions are registered using
     * the parameter block structure. Other functions are then
     * registered dynamically by the factory functions.
     *
     * This means that a single matching rule plug-in may handle
     * a number of different matching rules.                           */
    rc  = slapi_pblock_set(
        pb,
        SLAPI_PLUGIN_MR_INDEXER_CREATE_FN,
        (void *)plg_indexer_create
    );
    rc |= slapi_pblock_set(
        pb,
        SLAPI_PLUGIN_MR_FILTER_CREATE_FN,
        (void *)plg_filter_create
    );
    rc |= slapi_pblock_set(
        pb,
        SLAPI_PLUGIN_DESCRIPTION,
        (void *)&plg_desc
    );

    /* Register the matching rules themselves. */

    return rc;
}

ここで、plg_init()はプラグイン初期化関数、plg_indexer_create()はインデクサ・ファクトリ、plg_filter_create ()はフィルタ・ファクトリおよびplg_descはプラグイン説明構造体です。

プラグインでプライベート・データを使用する場合は、パラメータ・ブロックでSLAPI_PLUGIN_PRIVATEをプライベート・データ構造体に対するポインタとして設定してください。

例10-2 一致ルールの登録(matchingrule.c)

初期化関数でslapi_pblock_set()を使用するのではなく、ここに示すとおりslapi_matchingrule_register()を使用して一致ルールを登録します。

#include "slapi-plugin.h"

#define PLG_DESC      "Case Exact Matching on Directory String" \
                      " [defined in X.520]"
#define PLG_NAME      "caseExactMatch"
/* This OID is for examples only and is not intended for reuse. The
 * official OID for this matching rule is 2.5.13.5.                    */
#define PLG_OID       "1.3.6.1.4.1.42.2.27.999.4.1"

#ifdef _WIN32
__declspec(dllexport)
#endif
int
plg_init(Slapi_PBlock * pb)
{
    Slapi_MatchingRuleEntry * mrentry = slapi_matchingrule_new();
    int                       rc;
        
    /* Register matching rule factory functions.*/

    /* Matching rules themselves are registered using a
     * Slapi_MatchingRuleEntry structure, not the parameter
     * block structure used when registering plug-in functions.
     *
     * This plug-in registers only one matching rule. Yours
     * may register many matching rules.                               */
    rc |= slapi_matchingrule_set(
        mrentry,
        SLAPI_MATCHINGRULE_DESC,
        (void *)slapi_ch_strdup(PLG_DESC)
    );
    rc |= slapi_matchingrule_set(
        mrentry,
        SLAPI_MATCHINGRULE_NAME,
        (void *)slapi_ch_strdup(PLG_NAME)
    );
    rc |= slapi_matchingrule_set(
        mrentry,
        SLAPI_MATCHINGRULE_OID,
        (void *)slapi_ch_strdup(PLG_OID)
    );
    rc |= slapi_matchingrule_set(
        mrentry,
        SLAPI_MATCHINGRULE_SYNTAX,     /* Here you use DirectoryString.*/
        (void *)slapi_ch_strdup("1.3.6.1.4.1.1466.115.121.1.15")
    );
    rc |= slapi_matchingrule_register(mrentry);
    slapi_matchingrule_free(&mrentry, 1);

    return rc;
}
  • PLG_DESCは、一致ルールを説明する文字列です。

  • PLG_NAMEは一致ルールの文字列識別子です。

  • PLG_OIDは一致ルールのオブジェクト識別子です。

    サンプル・プラグインではすべての項目が#define (定義)されます。プラグインで複数の一致ルールを実装する場合、初期化関数では各項目を登録する必要があります。

    プラグインでは、slapi_pblock_set()を使用してファクトリ関数を個別に登録する必要があることに注意してください。

10.3 拡張可能な一致フィルタの操作

この項では、一致ルールに対応する拡張可能な一致フィルタの操作方法を具体的に説明します。すべての一致ルール・プラグインで、フィルタ一致を使用可能にする必要があります。

10.3.1 Directory Serverによる拡張可能な一致検索の処理方法

次のプロセスは、Directory Serverによる拡張可能な一致検索の処理方法を示しています。

  1. Directory Serverでは、拡張可能な一致フィルタを含む検索リクエストを受け取ると、対応する一致ルールを処理するプラグイン内のフィルタ・ファクトリ関数をコールします。サーバーからフィルタ・ファクトリに、拡張可能な一致フィルタ情報を含むパラメータ・ブロックが渡されます。

  2. フィルタ・ファクトリ関数により、フィルタ・オブジェクトが構築されます。続けて関数によって、オブジェクトに対するポインタおよび適切なフィルタ一致およびフィルタ索引関数が設定されます。

  3. サーバーでは、ディレクトリ全体を検索するのではなく、1つの索引内で一連の結果を検索しようとします。

    索引を読み取るために、サーバーでは、適切なインデクサ関数を見つけるために役立つフィルタ索引関数をコールします。

    Directory Serverではディレクトリ内の全エントリのみが考慮されるため、次のいずれかの状況が当てはまる場合、検索速度が大幅に低下する可能性があります。

    • 検索に適用される既存の索引がない場合

    • プラグインでインデクサ関数が指定されていない場合

    • 指定された値に対するキーがプラグインにより生成されない場合

    Directory Serverでは、インデクサ関数をコールしてキーを生成します。この関数の詳細は、「インデクサ関数」を参照してください。

  4. Directory Serverにより、候補エントリのリストが作成されます。

  5. エントリが検索結果としてクライアントに戻される前に、Directory Serverによって、エントリが検索範囲内にあることが検証されます。

  6. Directory Serverによって、操作に割り当てられていたメモリーが解放されます。

次の図は、Directory Serverによる検索リクエストの処理方法を示します。

図10-1 Directory Serverによる拡張可能な一致検索の実行

図10-1の説明が続きます
「図10-1 Directory Serverによる拡張可能な一致検索の実行」の説明

主なフィルタ関数は次のとおりです。

10.3.2 フィルタ一致関数

フィルタ一致関数では、フィルタ・オブジェクト、エントリおよび最初の属性へのポインタを取得して一致をチェックします。

次の図に、Directory Serverによるフィルタ一致関数の使用方法を示します。

図10-2 フィルタ一致関数のコンテキスト

図10-2の説明が続きます
「図10-2 フィルタ一致関数のコンテキスト」の説明

フィルタ一致関数からは、処理された各エントリについて0 (一致)、-1 (一致なし)またはLDAPエラー・コードが戻されることに注意してください。

例10-3 フィルタ一致関数(matchingrule.c)

この例では、2つのberval構造体が一致した場合に一致が発生する、大/小文字の完全一致ルールのフィルタ一致関数を示しています。

#include "slapi-plugin.h"

typedef struct plg_filter_t            /* For manipulating filter obj. */
{   char          *  f_type;           /* Attribute type to match      */
    int              f_op;             /* Type of comparison
                                        * (<, <=, ==,>=,>, substr)
                                        * for the filter.              */
    struct berval ** f_values;         /* Array of values to match     */
} plg_filter_t;

/* Check for a match against the filter.
 * Returns:  0 filter matched
 *          -1 filter did not match
 *        > 0 an LDAP Error code                                      */
static int
plg_filter_match(
    void        * obj,                 /* Matching rule object         */
    Slapi_Entry * entry,               /* Entry to match               */
    Slapi_Attr  * attr                 /* Attributes to match          */
)
{
    plg_filter_t  * fobj  = (plg_filter_t *)obj;
    struct berval * mrVal = NULL;      /* Values handled as bervals... */
    Slapi_Value   * sval;              /* ...and as Slapi_Value structs*/
    int             rc    = -1;        /* No match                     */

    if (fobj && fobj->f_type && fobj->f_values && fobj->f_values[0]) {

        mrVal = fobj->f_values[0];

        /* Iterate through the attributes, matching subtypes.          */
        for (; attr != NULL; slapi_entry_next_attr(entry, attr, &attr)) {

            char * type = NULL;        /* Attribute type to check      */

            if ((slapi_attr_get_type(attr, &type) == 0) &&
                (type != NULL)                          &&
                (slapi_attr_type_cmp(fobj->f_type, type, 2) == 0)
            ) { /* slapi_attr_type_cmp(type1, type2, ==>2<==)
                 * matches subtypes, too. Refer to the reference
                 * documentation for details.                          */

                /* Type and subtype match, so iterate through the
                 * values of the attribute.                            */
                int hint = slapi_attr_first_value(attr, &sval);
                while (hint != -1) {
                    const struct berval * val =
                        slapi_value_get_berval(sval);

                    /* The case exact matching rule
                     * compares the two bervals.
                     *
                     * Your matching rule may do
                     * lots of different checks here.                  */
                    rc = slapi_berval_cmp(val, mrVal);
                    if (rc == 0)  {    /* Successful match             */
                    /* If you have allocated memory for a custom
                     * matching rule, do not forget to release it.     */
                        return 0;
                    }

                    hint = slapi_attr_next_value(attr, hint, &sval);
                }
            }
        }
    }
    return rc;
}

大/小文字の完全一致のチェックには、バイトごとの比較を実行するslapi_berval_cmp ()のみが関与することに注意してください。ユーザー独自のプラグインでは、比較のためにより複雑な処理が実行される場合があります。

10.3.2.1 サブタイプの一致

属性を反復するコードで、slapi_attr_type_cmp ()が、その3番目の引数としてSLAPI_TYPE_CMP_SUBTYPEに割り当てられた値である2を取得することに注意してください。引数によって、属性のタイプに加えて、属性のロケールといった属性のサブタイプの比較が強制されます。プラグインAPI関数およびその引数の詳細は、「プラグインAPIリファレンス」を参照してください。

10.3.2.2 スレッド・セーフティおよびフィルタ一致関数

Directory Serverでは、同じフィルタ・オブジェクトのフィルタ一致関数を同時にコールすることはありません。ただし、Directory Serverでは、異なるフィルタ・オブジェクトの関数を同時にコールすることはできます。グローバル変数を使用する場合は、フィルタ一致関数でそれらの変数が安全に処理されることを確認してください。

10.3.3 フィルタ索引関数

フィルタ索引関数では、Directory Serverからパラメータ・ブロックを取得します。また、この関数では、パラメータ・ブロック内にポインタを設定して、サーバーが索引を読み取ることができるようにします。

例10-4 フィルタ索引関数(matchingrule.c)

この例では、値としてキーが等しい大/小文字の完全一致ルールのフィルタ索引関数を示します。

#include "slapi-plugin.h"

#define PLG_OID       "1.3.6.1.4.1.42.2.27.999.4.1"
#define SUBSYS        "CaseExactMatching Plugin"

typedef struct plg_filter_t            /* For manipulating filter obj. */
{   char          *  f_type;           /* Attribute type to match      */
    int              f_op;             /* Type of comparison
                                        * (<, <=, ==,>=,>, substr)
                                        * for the filter.              */
    struct berval ** f_values;         /* Array of values to match     */
} plg_filter_t;

static int
plg_filter_index(Slapi_PBlock * pb)
{
    int            rc       = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
    void         * obj      = NULL;    /* Server lets the plug-in      */
    plg_filter_t * fobj;               /* handle the object type.      */
    int            query_op = SLAPI_OP_EQUAL; /* Only exact matches    */
        
    if (!slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &obj)) {

        fobj = (plg_filter_t *)obj;

        /* Case exact match requires no modifications to
         * the at this point. Your plug-in may however
         * modify the object, then set it again in the
         * parameter block.                                            */
        rc  = slapi_pblock_set(        /* This is for completeness.    */
            pb,                        /* Your plug-in may modify      */
            SLAPI_PLUGIN_OBJECT,       /* the object if necessary.     */
            fobj
        );
        rc |= slapi_pblock_set(        /* Set attr type to match.      */
            pb,
            SLAPI_PLUGIN_MR_TYPE,
            fobj->f_type
        );
        rc |= slapi_pblock_set(        /* Set fcn to obtain keys.      */
            pb,
            SLAPI_PLUGIN_MR_INDEX_FN,
            (void*)plg_index_entry
        );
        rc |= slapi_pblock_set(        /* Set values to obtain keys.   */
            pb,
            SLAPI_PLUGIN_MR_VALUES,
            fobj->f_values
        );
        rc |= slapi_pblock_set(        /* This is for completeness.    */
            pb,                        /* Your plug-in may set a       */
            SLAPI_PLUGIN_MR_OID,       /* different MR OID than the    */
            PLG_OID                    /* one in the parameter block   */
        );
        rc |= slapi_pblock_set(        /* <, <=, ==,>=,>, substr     */
            pb,                        /* In this case, ==             */
            SLAPI_PLUGIN_MR_QUERY_OPERATOR,
            &query_op
        );
    }

    return rc;
}

このコードでは、次の変数およびマクロを使用します。

  • fobj->ftypeは、フィルタで指定された属性タイプを示します。

  • plg_index_entry()は、値からキーを生成するためのインデクサ関数を示します。

  • fobj->valuesは、属性値のberval配列を指します。

  • PLG_OIDは、一致ルールのオブジェクト識別子です。

  • query_opは、フィルタの問合せ演算子を示します。

10.3.3.1 フィルタ索引関数の入力パラメータ

フィルタ索引関数では、パラメータ・ブロック内のSLAPI_PLUGIN_OBJECTからフィルタ・オブジェクトへのポインタを取得できます。

10.3.3.2 フィルタ索引関数の出力パラメータ

フィルタ索引関数では、Directory Serverに制御を戻す前に、少なくとも次の項目の値をパラメータ・ブロックに設定する必要があります。

  • SLAPI_PLUGIN_MR_INDEX_FN (キーを生成するためのインデクサへのポインタ)

  • SLAPI_PLUGIN_MR_OID

  • SLAPI_PLUGIN_MR_QUERY_OPERATOR

  • SLAPI_PLUGIN_MR_TYPE

  • SLAPI_PLUGIN_MR_VALUES

  • SLAPI_PLUGIN_OBJECT (ユーザーの関数により変更されている場合)

詳細は、第17章「パラメータ・ブロックのリファレンス」を参照してください。

10.3.3.3 スレッド・セーフティおよびフィルタ索引関数

Directory Serverでは、同じフィルタ・オブジェクトのフィルタ索引関数を同時にコールすることはありません。ただし、Directory Serverでは、異なるフィルタ・オブジェクトの関数を同時にコールすることはできます。グローバル変数を使用する場合は、使用する関数でそれらの変数が安全に処理されることを確認してください。

10.3.4 フィルタ・ファクトリ関数

フィルタ・ファクトリ関数では、Directory Serverからパラメータ・ブロックを取得します。次に、関数により、Directory Serverで一致をチェックする候補である候補エントリのリストをサーバーで作成できるようにパラメータが設定されます。

次の図は、フィルタ・ファクトリ関数の動作を示しています。

図10-3 フィルタ・ファクトリ関数のコンテキスト

図10-3の説明が続きます
「図10-3 フィルタ・ファクトリ関数のコンテキスト」の説明

次の例では、大/小文字の完全一致ルールのフィルタ・ファクトリ関数を示しています。

例10-5 フィルタ・ファクトリ関数(matchingrule.c)

#include "slapi-plugin.h"

#define PLG_OID       "1.3.6.1.4.1.42.2.27.999.4.1"
#define SUBSYS        "CaseExactMatching Plugin"

/* Functions to obtain connection information for logging.             */
static long mypblock_get_msgid( Slapi_PBlock * pb);
static int  mypblock_get_connid(Slapi_PBlock * pb);
static int  mypblock_get_opid(  Slapi_PBlock * pb);

typedef struct plg_filter_t            /* For manipulating filter obj. */
{   char          *  f_type;           /* Attribute type to match      */
    int              f_op;             /* Type of comparison
                                        * (<, <=, ==,>=,>, substr)
                                        * for the filter.              */
    struct berval ** f_values;         /* Array of values to match     */
} plg_filter_t;

static int
plg_filter_create(Slapi_PBlock * pb)
{
    int             rc       = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
    char          * mr_oid   = NULL;   /* MR OID from the server       */
    char          * mr_type  = NULL;   /* Attr type to match           */
    struct berval * mr_value = NULL;   /* Attr value to match          */
    plg_filter_t  * fobj     = NULL;   /* Object to create             */
        
    if (
        slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, &mr_oid) ||
        (mr_oid == NULL)
    ) {
        slapi_log_error_ex(
            -1, /* errorId */
            mypblock_get_msgid(pb),
            mypblock_get_connid(pb),
            mypblock_get_opid(pb),
            SUBSYS,
            SLAPI_INTERNAL_ERROR,
            "plg_filter_create failed: NULL OID values are invalid.\n"
        );
        }
    else if (strcmp(mr_oid, PLG_OID) == 0) {
        /* The MR OID from the server is handled by this plug-in.      */
        if (
            (slapi_pblock_get(pb, SLAPI_PLUGIN_MR_TYPE,  &mr_type) == 0)  &&
            (mr_type  != NULL)                                            &&
            (slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUE, &mr_value) == 0) &&
            (mr_value != NULL)
        ) { /* ...provide a pointer to a filter match function.        */
            int op            = SLAPI_OP_EQUAL;
            fobj              = (plg_filter_t *)slapi_ch_calloc(
                                    1,
                                    sizeof (plg_filter_t)
                                );
            fobj->f_type      = slapi_ch_strdup(mr_type);
            fobj->f_op        = op;
            fobj->f_values    = (struct berval **)slapi_ch_malloc(
                                    2 * sizeof(struct berval *)
                                );
            fobj->f_values[0] = slapi_ch_bvdup(mr_value);
            fobj->f_values[1] = NULL;

            rc  = slapi_pblock_set(        /* Set object destructor.   */
                pb,
                SLAPI_PLUGIN_DESTROY_FN,
                (void *)plg_filter_destroy
            );
            rc |= slapi_pblock_set(        /* Set object itself.       */
                pb,
                SLAPI_PLUGIN_OBJECT,
                (void  *)fobj
            );
            rc |= slapi_pblock_set(        /* Set filter match fcn.    */
                pb,
                SLAPI_PLUGIN_MR_FILTER_MATCH_FN,
                (void *)plg_filter_match
            );
            rc |= slapi_pblock_set(        /* Set sorting function.    */
                pb,
                SLAPI_PLUGIN_MR_FILTER_INDEX_FN,
                (void *)plg_filter_index
            );

            if (rc == 0) {
                slapi_log_info_ex(
                    SLAPI_LOG_INFO_AREA_PLUGIN,
                    SLAPI_LOG_INFO_LEVEL_DEFAULT,
                    mypblock_get_msgid(pb),
                    mypblock_get_connid(pb),
                    mypblock_get_opid(pb),
                    SUBSYS,
                    "plg_filter_create (oid %s; type %s) OK\n",
                    mr_oid, mr_type
                );
            } else {
                slapi_log_error_ex(
                    -1, /* errorId */
                    mypblock_get_msgid(pb),
                    mypblock_get_connid(pb),
                    mypblock_get_opid(pb),
                    SUBSYS,
                    SLAPI_INTERNAL_ERROR,
                    "plg_filter_create (oid %s; type %s) - pblock error \n",
                    mr_oid, mr_type
                );
            }
        } else { /* Missing parameters in the pblock                   */
            slapi_log_error_ex(
                -1,
                mypblock_get_msgid(pb),
                mypblock_get_connid(pb),
                mypblock_get_opid(pb),
                SUBSYS,
                "Parameter errors ",
                "plg_filter_create: invalid input pblock.\n"
            );
        }
    }

    return rc;
}

この関数では、パラメータ・ブロックで一致ルールOIDを処理しない場合、LDAP_UNAVAILABLE_CRITICAL_EXTENSIONを戻すことに注意してください。「不明な一致ルールの処理」を参照してください。

10.3.4.1 フィルタ・ファクトリ関数の入力パラメータ

フィルタ・ファクトリ関数では、パラメータ・ブロックから次の項目の値を取得できます。

  • SLAPI_PLUGIN_MR_OID

  • SLAPI_PLUGIN_MR_TYPE

  • SLAPI_PLUGIN_MR_VALUE

  • SLAPI_PLUGIN_PRIVATE (プラグイン初期化関数で指定されたプライベート・データがプラグインで使用されている場合)

10.3.4.2 フィルタ・ファクトリ関数の出力パラメータ

インデクサ・ファクトリ関数では、Directory Serverに制御を戻す前に、次の項目の値をパラメータ・ブロックに設定する必要があります。

  • SLAPI_PLUGIN_DESTROY_FN (フィルタ・オブジェクトのデストラクタへのポインタ)

  • SLAPI_PLUGIN_MR_FILTER_INDEX_FN (フィルタ索引関数へのポインタ)

  • SLAPI_PLUGIN_MR_FILTER_MATCH_FN (フィルタ一致関数へのポインタ)

  • SLAPI_PLUGIN_MR_FILTER_RESET_FN (必要な場合、フィルタ・リセット関数へのポインタ)

  • SLAPI_PLUGIN_MR_FILTER_REUSABLE (フィルタの再利用が可能であることを指定する必要がある場合)

  • SLAPI_PLUGIN_OBJECT (フィルタ・オブジェクトへのポインタ)

詳細は、第17章「パラメータ・ブロックのリファレンス」を参照してください。

10.3.4.3 スレッド・セーフティおよびフィルタ・ファクトリ関数

この関数はスレッド・セーフである必要があります。Directory Serverでは、この関数を同時にコールできます。

10.3.5 フィルタ・オブジェクト・デストラクタ関数

フィルタ・オブジェクト・デストラクタ関数では、フィルタ・ファクトリ関数によって設定されたフィルタ・オブジェクトに割り当てられていたメモリーを解放します。操作の完了後、Directory Serverによりデストラクタがコールされ、フィルタ・オブジェクトをSLAPI_PLUGIN_OBJECTの値として示すパラメータ・ブロックが渡されます。

Directory Serverにより、同じオブジェクトのデストラクタが同時にコールされることはありません。

例10-6 フィルタ・オブジェクトおよびデストラクタ(matchingrule.c)

このコードは、サンプル・オブジェクトおよびデストラクタを示します。

#include "slapi-plugin.h"

typedef struct plg_filter_t            /* For manipulating filter obj. */
{   char          *  f_type;           /* Attribute type to match      */
    int              f_op;             /* Type of comparison
                                        * (<, <=, ==,>=,>, substr)
                                        * for the filter.              */
    struct berval ** f_values;         /* Array of values to match     */
} plg_filter_t;


/* Free memory allocated for the filter object.                        */
static int
plg_filter_destroy(Slapi_PBlock * pb)
{
    void         * obj  = NULL;        /* Server lets the plug-in      */
    plg_filter_t * fobj = NULL;        /* handle the object type.      */

    if (!slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &obj))
    {
        fobj = (plg_filter_t *)obj;
        if (fobj){
            slapi_ch_free((void **)&fobj->f_type);
                if (fobj->f_values){
                    ber_bvecfree(fobj->f_values);
                }
            slapi_ch_free((void **)&fobj);
        }
    }
    return 0;
}

10.4 一致コールに従ったエントリの索引付け

この項では、一致ルールに基づくディレクトリ索引にプラグイン・サポートを提供する方法について説明します。プラグインでサポートされる一致ルールの索引付けを使用可能にするために、一致ルール・プラグインは必要ありません。


注意:

Directory Serverでは、ユーザーのプラグインに索引付け機能がない場合であっても、拡張可能な一致検索にそのプラグインを使用できます。

ただし、索引付けのサポートがない場合、Directory Serverではディレクトリ全体から検索結果を生成する必要があり、これは検索パフォーマンスに深刻な影響を与えます。


ディレクトリ索引によってクライアント検索が高速化します。Directory Serverでは、ディレクトリ全体を検索するのではなく、索引を通じて検索することにより、検索結果エントリのリストを作成できます。ディレクトリに多数のエントリが含まれている場合、索引によって検索パフォーマンスが大幅に向上します。したがって、ディレクトリ管理者は、定期的に検索される属性の索引をメンテナンスするようにディレクトリを構成します。

10.4.1 Directory Serverによる索引の処理方法

プラグインでサポートされるカスタム一致ルールの索引をメンテナンスするために、サーバーではインデクサ関数を必要とします。インデクサ関数では、属性値の索引キーへの変換が可能です。Directory Serverによって索引を作成するためにインデクサ関数がコールされ、その後は、索引に影響する可能性のある、属性値の追加、変更または削除といった変更時にコールされます。

カスタム一致ルールの索引を読み取るために、Directory Serverではフィルタ索引関数を必要とします。フィルタ・ファクトリ関数により、この関数へのポインタが提供されます。詳細は、「拡張可能な一致フィルタの操作」および「フィルタ索引関数」を参照してください。

Directory Serverでは、プラグインのインデクサ・ファクトリ関数を利用して索引付けオブジェクトを設定し、適切なインデクサ関数へのポインタを提供します。

次の図は、Directory Serverによる一致ルールに基づく索引付けの実行方法を示しています。

図10-4 Directory Serverによる一致ルールを使用した索引のメンテナンス

図10-4の説明が続きます
「図10-4 Directory Serverによる一致ルールを使用した索引のメンテナンス」の説明

図10-4に示したプロセスの概要は次のとおりです。

  1. Directory Serverによりパラメータ・ブロックが作成され、一致させる一致ルールOIDおよび属性タイプを示すようにパラメータが設定されます。続けて、Directory Serverによりインデクサ・ファクトリ関数がコールされます。

  2. インデクサ・ファクトリ関数によりパラメータ・ブロックが調べられ、必要に応じてインデクサ・オブジェクトが割り当てられます。関数によって、インデクサおよびフィルタ索引関数へのポインタも設定されます。必要な場合、関数では、Directory Serverに制御を戻す前に、デストラクタへのポインタを設定してインデクサ・オブジェクトを解放します。

  3. Directory Serverにより、キーに変換する属性値を示すようにパラメータ・ブロックが設定され、インデクサ関数がコールされます。

  4. インデクサ関数により値がキーに変換されます。インデクサが戻されたら、Directory Serverではキーを使用して索引を更新します。

  5. Directory Serverによりパラメータ・ブロックが解放されます。必要に応じて、サーバーでは指定されたデストラクタを使用してインデクサ・オブジェクトを解放します。

Directory Serverではインデクサ・ファクトリ関数を同時にコールできることに注意してください。そのため、インデクサ・ファクトリ関数はスレッド・セーフである必要があります。

主なフィルタ関数は次のとおりです。

10.4.2 インデクサ関数

インデクサ関数では、属性値のberval配列へのポインタを含むパラメータ・ブロックをDirectory Serverから取得します。関数では続けて、値から対応するキーのberval配列を生成します。最後に、関数により、パラメータ・ブロックにキーへのポインタが設定されます。

次の図に、Directory Serverによるインデクサ関数の使用方法を示します。

図10-5 インデクサ関数のコンテキスト

図10-5の説明が続きます
「図10-5 インデクサ関数のコンテキスト」の説明

次の例では、値としてキーが等しい大/小文字の完全一致ルールのインデクサ関数を示します。

例10-7 インデクサ関数(matchingrule.c)

#include "slapi-plugin.h"

typedef struct plg_filter_t            /* For manipulating filter obj. */
{   char          *  f_type;           /* Attribute type to match      */
    int              f_op;             /* Type of comparison
                                        * (<, <=, ==,>=,>, substr)
                                        * for the filter.              */
    struct berval ** f_values;         /* Array of values to match     */
} plg_filter_t;

static int
plg_index_entry(Slapi_PBlock * pb)
{
    int              rc     = LDAP_OPERATIONS_ERROR;
    void          *  obj    = NULL;    /* Server lets the plug-in      */
    plg_filter_t  *  fobj;             /* handle the object type.      */
    struct berval ** values;           /* Values from server           */
        
    if (slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &obj) == 0) {
        fobj = (plg_filter_t *)obj;
        if (
            (slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &values) == 0) &&
            (values != NULL)
        ) {
                
            /* The case exact match builds the index keys
             * from the values by copying the values because
             * the keys and values are the same.
             *
             * Your matching rule may do something quite
             * different before setting the keys associated
             * with the values in the parameter block.                 */
            rc = slapi_pblock_set(     /* Set keys based on values.    */
                pb,
                SLAPI_PLUGIN_MR_KEYS,
                slapi_ch_bvecdup(values)
            );
        }
    }

    return rc;
}

ここで、objはインデクサ・オブジェクトを指し、valuesは属性値のberval配列を指します。失敗した場合、関数からLDAP_OPERATIONS_ERRORが戻されることに注意してください。厳密には、LDAP_OPERATIONS_ERRORはLDAP操作の順序付けが間違っていることを示します。歴史的な理由により、このコンテキストで使用される場合、このエラーは内部エラーを示します。

10.4.2.1 インデクサの入力パラメータ

インデクサ関数では、パラメータ・ブロックから次の項目の値を取得できます。

  • SLAPI_PLUGIN_MR_VALUES

  • SLAPI_PLUGIN_MR_OBJECT

10.4.2.2 インデクサの出力パラメータ

インデクサ関数では、キーのberval配列を生成する必要があります。関数では、Directory Serverに制御を戻す前に、パラメータ・ブロックでSLAPI_PLUGIN_MR_KEYSを設定する必要があります。詳細は、「プラグインAPIリファレンス」を参照してください。

10.4.2.3 スレッド・セーフティおよびインデクサ

Directory Serverにより、同じインデクサ・オブジェクトのインデクサが同時にコールされることはありません。ただし、Directory Serverでは、異なるインデクサ・オブジェクトの関数を同時にコールすることはできます。グローバル変数を使用する場合は、使用する関数でそれらの変数が安全に処理されることを確認してください。

10.4.3 インデクサ・ファクトリ関数

インデクサ・ファクトリ関数では、Directory Serverからパラメータ・ブロックを取得します。関数により、Directory Serverで一致ルールに基づいて索引を更新したり結果をソートできるようにパラメータが設定されます。

次の図に、Directory Serverによるインデクサ・ファクトリ関数の使用方法を示します。

図10-6 インデクサ・ファクトリ関数のコンテキスト

図10-6の説明が続きます
「図10-6 インデクサ・ファクトリ関数のコンテキスト」の説明

次の例では、大/小文字の完全一致ルールのインデクサ・ファクトリ関数を示しています。

例10-8 インデクサ・ファクトリ関数(matchingrule.c)

#include "slapi-plugin.h"

#define PLG_OID       "1.3.6.1.4.1.42.2.27.999.4.1"
#define SUBSYS        "CaseExactMatching Plugin"

/* Functions to obtain connection information for logging.             */
static long mypblock_get_msgid( Slapi_PBlock * pb);
static int  mypblock_get_connid(Slapi_PBlock * pb);
static int  mypblock_get_opid(  Slapi_PBlock * pb);

static int
plg_indexer_create(Slapi_PBlock * pb)
{
    int    rc     = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* Init failed*/
    char * mr_oid = NULL;              /* MR OID from the server       */
    
    if (slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, mr_oid) ||
        (mr_oid == NULL)) {
        slapi_log_error_ex(
            -1, /* errorId */
            mypblock_get_msgid(pb),
            mypblock_get_connid(pb),
            mypblock_get_opid(pb),
            SUBSYS,
            SLAPI_INTERNAL_ERROR,
            "plg_indexer_create failed: NULL OID values are invalid.\n"
        );
    } else if (strcmp(mr_oid, PLG_OID) == 0) {
        if ( /* The MR OID from the server is handled by this plug-in. */
            (slapi_pblock_set(         /* This is for completeness.    */
                pb,                    /* Your plug-in may set a       */
                SLAPI_PLUGIN_MR_OID,   /* different OID than the one   */
                PLG_OID                /* provided by the server.      */
            ) == 0) &&
            (slapi_pblock_set(         /* Provide an appropriate       */
                pb,                    /* indexer function pointer.    */
                SLAPI_PLUGIN_MR_INDEX_FN,
                (void *)plg_index_entry
            ) == 0) &&
            (slapi_pblock_set(         /* Set the object destructor.   */
                pb,
                SLAPI_PLUGIN_DESTROY_FN,
                (void *)plg_filter_destroy
            ) == 0)) {
                rc = LDAP_SUCCESS;
        } else {
            slapi_log_error_ex(
                -1, /* errorId */
                mypblock_get_msgid(pb),
                mypblock_get_connid(pb),
                mypblock_get_opid(pb),
                SUBSYS,
                SLAPI_INTERNAL_ERROR,
                "plg_indexer_create failed %d \n", rc
            );
        }
    }
    
    return rc;
}

ここで、PLG_OIDは一致ルールのオブジェクト識別子です。plg_index_entry()はインデクサです。plg_filter_destroy ()はデストラクタです。失敗した場合、関数からLDAP_UNAVAILABLE_CRITICAL_EXTENSIONが戻されることに注意してください。

10.4.3.1 インデクサ・ファクトリ関数の入力パラメータ

インデクサ・ファクトリ関数では、パラメータ・ブロックから次の項目の値を読み取ることができます。

  • SLAPI_PLUGIN_MR_OID

  • SLAPI_PLUGIN_MR_TYPE

  • SLAPI_PLUGIN_MR_USAGE (結果をソートする必要があるかどうかを示します)

  • SLAPI_PLUGIN_PRIVATE (プラグイン初期化関数で指定するプライベート・データがプラグインで使用される場合)

10.4.3.2 インデクサ・ファクトリ関数の出力パラメータ

インデクサ・ファクトリ関数では、Directory Serverに制御を戻す前に、少なくとも次の項目の値をパラメータ・ブロックに設定する必要があります。

  • SLAPI_PLUGIN_DESTROY_FN (インデクサ・オブジェクト・デストラクタへのポインタ)

  • SLAPI_PLUGIN_MR_INDEX_FN (インデクサへのポインタ)

  • SLAPI_PLUGIN_OBJECT (インデクサ・オブジェクトへのポインタ)

パラメータ・ブロックの詳細は、第17章「パラメータ・ブロックのリファレンス」を参照してください。

10.4.3.3 スレッド・セーフティおよびインデクサ・ファクトリ関数

この関数はスレッド・セーフである必要があります。Directory Serverでは、この関数を同時にコールできます。

10.4.4 インデクサ・オブジェクト・デストラクタ関数

インデクサ・オブジェクト・デストラクタ関数では、インデクサ・ファクトリ関数によって設定されたインデクサ・オブジェクトに割り当てられていたメモリーを解放します。Directory Serverでは、索引操作の完了後にデストラクタをコールします。

インデクサ・オブジェクト・デストラクタでは、フィルタ・オブジェクト・デストラクタと同様に、パラメータ・ブロックを唯一の引数として取得します。パラメータ・ブロックでは、オブジェクトへのポインタをSLAPI_PLUGIN_OBJECTに保持します。詳細は、「フィルタ・オブジェクト・デストラクタ関数」を参照してください。

Directory Serverにより、同じオブジェクトのデストラクタが同時にコールされることはありません。

10.5 一致ルールに従ったソートの使用可能化

クライアントでは、拡張可能な一致検索からの結果をソートするようにDirectory Serverに要求できます。この項では、一致ルールに基づいてソートを使用可能にする方法について説明します。

10.5.1 Directory Serverによる一致ルールに従ったソートの実行方法

Directory Serverでは、索引付けのバリエーションとしてソートを実行し、インデクサ関数によって生成されたキーを使用して結果をソートします。このプロセスは、次のとおりです。

  1. Directory Serverにより索引付け用のパラメータ・ブロックが作成され、そのパラメータ・ブロックをインデクサ・ファクトリ関数に渡す前にSLAPI_PLUGIN_MR_USAGESLAPI_PLUGIN_MR_USAGE_SORTに設定されます。

  2. インデクサ・ファクトリ関数では、索引付けに関するパラメータをパラメータ・ブロックに設定する必要があります。

    ソート関数が通常のインデクサ関数とは異なる場合は、その関数でSLAPI_PLUGIN_MR_USAGEの値がチェックされることを確認し、SLAPI_MR_INDEXER_FNを適宜設定します。

  3. Directory Serverにより、パラメータ・ブロックで、SLAPI_PLUGIN_MR_VALUESがソートされる値へのポインタとして設定されます。続けてDirectory Serverからパラメータ・ブロックにインデクサ関数が渡されます。

  4. Directory Serverで、インデクサ関数によりSLAPI_PLUGIN_MR_KEYSに設定されたキーに基づいて結果がソートされます。

  5. Directory Serverによって、操作に割り当てられていたメモリーが解放されます。

    一致ルール・プラグインにより、どのようにして、Directory Serverで一致ルールに基づく索引付けの実行が可能になるかの詳細は、「一致ルールに従ったエントリの索引付け」を参照してください。

10.6 不明な一致ルールの処理

この項では、Directory Serverにより認識されない一致ルールOIDのプラグインをDirectory Serverで見つける方法について説明します。

10.6.1 対応の内部リスト

Directory Serverでは、OIDにより一致ルールを識別します。サーバーでは、どの一致ルール・プラグインで、どのOIDが処理されるかの内部リストを保持します。

Directory Serverでは、一致ルールOIDを含む拡張可能な一致フィルタ検索リクエストをサーバーで受け取ったときに、どのプラグインをコールするかを、内部リストを使用して決定します。Directory Serverでは最初に、プラグイン初期化関数内のslapi_matchingrule_register()を使用してプラグインで処理されるOIDが、一致ルール・プラグインにより登録されるときにリストを作成します。

10.6.2 内部リストに含まれないOID

リストに含まれない一致ルールOIDが検出された場合、Directory Serverでは登録済のファクトリ関数を使用して各一致ルール・プラグインを問い合せます。一致ルール・プラグインごとに、OIDを含むパラメータ・ブロックがDirectory Serverから一致ルール・ファクトリ関数に渡されます。サーバーでは次に、ファクトリ関数にパラメータ・ブロック内のポインタが戻されているかどうかをチェックします。このポインタにより、OIDの適切な索引付けまたは一致関数が識別されます。

ファクトリ関数により適切な関数へのポインタが設定されている場合、Directory Serverではプラグインが一致ルールをサポートしているとみなします。

プラグインにより特定のフィルタ一致操作が処理されるかどうかをDirectory Serverでチェックする方法は、次のとおりです。索引付けのプロセスは、一致のプロセスと非常に類似しています。

図10-7 一致ルール・プラグインでの不明なOIDの検索

図10-7の説明が続きます
「図10-7 一致ルール・プラグインでの不明なOIDの検索」の説明

図10-7に示したプロセスの概要は次のとおりです。

  1. Directory Serverにより、OIDを処理するためのプラグインの内部リストで一致が検出されません。そのためサーバーでは、パラメータ・ブロックを作成し、SLAPI_PLUGIN_MR_OIDなどのファクトリの適切なパラメータを設定します。

  2. Directory Serverによりファクトリ関数がコールされます。ファクトリ関数により、一致コールを処理するための適切な関数へのポインタがパラメータ・ブロックに設定されるか、ポインタがNULLのままにされます。

  3. Directory Serverにより、ファクトリ関数が戻された後でパラメータがチェックされます。ファクトリ関数によりパラメータ・ブロックに関数ポインタが設定されている場合、Directory Serverで内部リストが更新されます。これにより、関数で、OIDに関連付けられている一致ルール操作をサポートするプラグインが示されます。そうでない場合、ポインタはNULLのままになり、Directory Serverでは登録されている次の一致ルール・プラグインで再度処理を試みます。

    すべての一致ルール・プラグインをコールしても、Directory Serverにより一致ルールOIDを処理するためのプラグインが見つからない場合、サーバーからクライアントにLDAP_UNAVAILABLE_CRITICAL_EXTENSIONが戻されます。

  4. Directory Serverによって、操作に割り当てられていたメモリーが解放されます。

    Directory Serverでは、対応の内部リストを拡張する目的で、プラグイン・ファクトリ関数がコールされることに注意してください。