カスタムポリシーの開発

カスタムポリシーは、アノテーション付きの Java クラスです。このアノテーションは、このクラスをカスタムポリシーとしてマークするとともに、このクエリの実行前にクエリをインターセプトするためにサーバーが実行する必要があるメソッドを示すものです。

カスタムポリシーが実行されるたびに、サーバーはそのクラスの新しいインスタンスを作成します。しかし、この Java クラスの属性が「静的」であると、ポリシーを何度実行しても属性の値は変わりません。

カスタムポリシーを開発するには、プロジェクトのクラスパスに <DENODO_HOME>/lib/contrib/denodo-commons-custom.jar を追加します。

Virtual DataPort API Javadoc は、この API のクラスとアノテーションについてのドキュメントを提供します。

<DENODO_HOME>/samples/vdp/customPolicies/ ディレクトリには、サンプルのカスタムポリシーがあります。

このカスタムポリシーは、ユーザーまたはロールが同じビューやストアドプロシージャに対して同時に実行できるクエリの数を制限します。このカスタムポリシーには「Limit」という入力パラメーターが 1 つあります。このパラメーターにより、そのユーザーまたはロールが同時に実行できるクエリの最大数を設定します。

このディレクトリの README ファイルでは、このサンプルをコンパイルして Virtual DataPort にインポートする方法について説明しています。

カスタムポリシーを開発して Virtual DataPort にインポートした後は、Denodo ナレッジベースの記事「 How to debug Denodo custom extensions with Eclipse 」を読んでデバッグ方法について確認してください。


カスタムポリシーを開発するには、次のような Java クラスを作成します。

import com.denodo.common.custom.annotations.*;
import com.denodo.common.custom.policy.*;

@CustomElement(name = "my_new_custom_policy", type = CustomElementType.VDPCUSTOMPOLICY)
public class MyDenodoCustomPolicy {

    @CustomContext
    CustomRestrictionPolicyContext context;

    @CustomExecutor
    public CustomRestrictionPolicyValue execute(
        @CustomParam(name = "parameter1", mandatory = false) String inputParameter {

       /*
        * This custom policy accepts all the queries that involve
        * the view over which this policy was assigned.
        */
        return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT);
   }
}

@CustomElementname 属性は、このカスタムポリシーの名前です。

context 属性により、クエリのコンテキストについて以下の情報を取得できます。

  • Virtual DataPort が受け取ったクエリ: getQuery()

  • クエリに含まれるフィールド。つまり、 SELECTWHEREGROUP BY 、および HAVING の句に含まれるフィールドのリスト: getFieldsInQuery()

  • クエリを実行するユーザーアカウント: getCurrentUserName()

  • クエリを実行するユーザーアカウントの有効なロールのリスト: getCurrentUserRoles() 。つまり、そのユーザーに直接付与されているロールと、ユーザー自身のロールではなく、ユーザーのロールに付与されているロール。

  • クエリを実行するコネクションのユーザーエージェント: getCurrentUserAgent()

  • クエリが実行されるデータベース: getCurrentDatabaseName() 。これはビューが属するデータベースと異なる場合があります。たとえば、データベース「db1」に接続しているときに、 SELECT * FROM db2.customer を実行した場合、このメソッドは「db1」を返します。

  • このカスタムポリシーが割り当てられているユーザーまたはロール: getPolicyCredentialsName() および getPolicyCredentialsType() 。後者のメソッドは、そのポリシーがユーザーとロールのどちらに割り当てられているかを返します。

  • このカスタムポリシーが割り当てられているビューまたはストアドプロシージャ: getElementType() および getElementName()

  • クエリのプロパティ。プロパティの値を取得するには getProperty(...) を呼び出し、値を変更するには setProperty(...) を呼び出します。使用可能なプロパティは、 CustomRestrictionPolicyContext クラスで定義されている定数 (I18N_PROPERTYSWAP_PROPERTY など) です。

  • JMX を介してデータを取得するためにこのカスタムポリシーで使用できる、Virtual DataPort サーバーへの JMX コネクション: getJmxConnection() 。Denodo の JMX インターフェイスは、サーバーの現在のステータスに関する情報を提供します。この情報を使用して、Denodo サーバーの負荷や同時クエリ数などに基づいてポリシーの動作を変更できます。

  • メッセージをログに記録するには、 log(...) メソッドを呼び出します。このメソッドを使用して記録されたメッセージは、ログカテゴリ com.denodo.vdb.catalog.view.CustomRestrictionPolicyContextImpl にリダイレクトされます。

  • オプションの完全なリストについては、 CustomRestrictionPolicyContext クラスの Javadoc を参照してください。

注釈

カスタムポリシーのメカニズムでは、 execute メソッドの呼び出しの直前に context 属性が初期化されます。クラスのコンストラクターからこの属性にアクセスしようとすると、この属性は null になります。

カスタムポリシーにパラメーターを追加するには、 execute メソッドにパラメーターを追加して、 @CustomParam(name = "<parameter_name>", mandatory = false) というアノテーションを付けます。このアノテーションには以下の 2 つのパラメーターがあります。

  • name: この値は、Administration Tool でこのカスタムポリシーに関する情報をユーザーに表示するときに使用されます。

  • mandatory: このパラメーターが必須かどうかを示すブール値。

後でこのポリシーをビュー上でユーザーまたはロールに割り当てる場合は、ポリシーの入力パラメーターの値を指定する必要があります。

この Java クラスには、 @CustomExecutor のアノテーションが付いたメソッドが 1 つだけ 必要です (この例では、 execute メソッド)。実行エンジンは、クエリの実行時にカスタムポリシーを読み込むと、このアノテーションによってマークされたメソッドを実行します。このメソッドは CustomRestrictionPolicyValue オブジェクトを返す必要があります。

  • クエリを「そのまま」承認するには、以下を返します。

    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT);
    
  • クエリを拒否するには、以下を返します。

    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.REJECT);
    
  • クエリに条件を追加するには、以下を返します。

    String condition = "title <> 'Chief Executive Officer'";
    return new CustomRestrictionPolicyValue(
                   CustomRestrictionPolicyType.ACCEPT_WITH_FILTER
                   , CustomRestrictionPolicyFilterType.REJECT_ROW
                   , condition
                   , null);
    

    この例では、実行エンジンは、ユーザーが実行するクエリに、条件「title <> 'Chief Executive Officer'」を追加します。

  • フィールドのリストに含まれる 1 つ以上のフィールドがクエリに含まれている場合にクエリに条件を追加するには、以下を返します。フィールドが SELECTWHEREGROUP BYHAVING の句の少なくとも 1 つで使用されている場合、そのフィールドはクエリで使用されているとみなされます。

    String condition = "title <> 'Chief Executive Officer'";
    Set<String> sensitiveFields = new HashSet<>(Arrays.asList("salary", "bonus"));
    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT_WITH_FILTER,
                   CustomRestrictionPolicyFilterType.REJECT_ROW_IF_ANY_SENSITIVE_FIELDS_USED
                   , condition
                   , sensitiveFields);
    

    この例では、「salary」フィールドと「bonus」フィールドの 両方またはどちらか がクエリで使用されている場合、条件「title <> 'Chief Executive Officer'」がクエリに追加されます。これらのフィールドのどちらもクエリで使用されていない場合、この条件はクエリに追加 されません

  • フィールドのリストに含まれるすべてのフィールドがクエリに含まれている場合にクエリに条件を追加するには、以下を返します。フィールドが SELECTWHEREGROUP BYHAVING の句の少なくとも 1 つで使用されている場合、そのフィールドはクエリで使用されているとみなされます。

    String condition = "title <> 'Chief Executive Officer'";
    Set<String> sensitiveFields = new HashSet<>(Arrays.asList("salary", "bonus"));
    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT_WITH_FILTER,
                    CustomRestrictionPolicyFilterType.REJECT_ROW_IF_ALL_SENSITIVE_FIELDS_USED, condition,
                    sensitiveFields);
    

    この例では、「salary」フィールドと「bonus」フィールドの両方がクエリで使用されている場合、条件「title <> 'Chief Executive Officer'」がクエリに追加されます。これらのフィールドが両方とも使用されているのでなければ、この条件はクエリに追加 されません

    この例では、定数 REJECT_ROW_IF_ALL_SENSITIVE_FIELDS_USED を使用し、前の例では定数 REJECT_ROW_IF_ANY_SENSITIVE_FIELDS_USED を使用している点に注意してください。

  • フィールドのリストに含まれる 1 つ以上のフィールドがクエリで使用されている場合に、特定の条件を満たして いない 行で、リストに含まれるフィールドの値をマスクするには、以下を返します。

    String condition = "title <> 'Chief Executive Officer'";
    Set<String> sensitiveFields = new HashSet<>(Arrays.asList("salary", "bonus"));
    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT_WITH_FILTER,
                    CustomRestrictionPolicyFilterType.MASK_SENSITIVE_FIELDS_IF_ANY_USED, condition,
                    sensitiveFields);
    

    フィールドをマスクするには、その値を null に設定します。

    この例では、「salary」フィールドと「bonus」フィールドの 両方またはどちらか がクエリで使用されている場合、条件を満たして いない 行で、「sensitiveFields」リストに含まれるフィールド (「salary」と「bonus」) が NULL に設定されます。この例では、「title」フィールドの値が「Chief Executive Officer」になっている (つまり、条件を満たしていない) 行で、「salary」フィールドと「bonus」フィールドの値が NULL に設定されます。

    これらのフィールドのいずれもクエリで使用されていなければ、どのフィールドもマスクされません。

  • フィールドのリストに含まれるすべてのフィールドがクエリで使用されている場合に、条件を満たして いない 行で、リストに含まれるフィールドの値をマスクするには、以下を返します。

    String condition = "title <> 'Chief Executive Officer'";
    Set<String> sensitiveFields = new HashSet<>(Arrays.asList("salary", "bonus"));
    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT_WITH_FILTER,
                    CustomRestrictionPolicyFilterType.MASK_SENSITIVE_FIELDS_IF_ALL_USED, condition,
                    sensitiveFields);
    

    フィールドをマスクするには、その値を null に設定します。

    この例では、「salary」フィールドと「bonus」フィールドの 両方 がクエリで使用されている場合、条件を満たして いない 行で、「sensitiveFields」リストに含まれるフィールド (「salary」と「bonus」) が NULL に設定されます。この例では、「title」フィールドの値が「Chief Executive Officer」になっている (つまり、条件を満たしていない) 行で、「salary」フィールドと「bonus」フィールドの値が NULL に設定されます。

    これらのフィールドのすべてがクエリで使用されているのでなければ、条件はクエリに追加 されず 、どのフィールドもマスクされません。

  • クエリの結果のすべての行で一部のフィールドの値をマスクする (つまり、 MASK_SENSITIVE_FIELDS_IF_ALL_USED または MASK_SENSITIVE_FIELDS_IF_ANY_USED オプションを指定する) には、常に false に評価される条件 (1 is null など) を使用します。

    String condition = "1 is null";
    Set<String> sensitiveFields = new HashSet<>(Arrays.asList("salary", "bonus"));
    return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT_WITH_FILTER,
                    CustomRestrictionPolicyFilterType.MASK_SENSITIVE_FIELDS_IF_ANY_USED, condition,
                    sensitiveFields);
    

    この例では、「salary」フィールドと「bonus」フィールドの 両方またはどちらか がクエリで使用されている場合、すべての行で「salary」フィールドと「bonus」フィールドの値が NULL に設定されます。


カスタムポリシーの入力パラメーターのいずれかが日時値の場合は、カスタム関数での「 日時型および時間間隔型の処理 」を参照してください。カスタムポリシーの入力パラメーターの管理規則は、カスタム関数の場合と同じです。