カスタムポリシーの開発¶
カスタムポリシーは、アノテーション付きの 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);
}
}
@CustomElement
の name
属性は、このカスタムポリシーの名前です。
context
属性により、クエリのコンテキストについて以下の情報を取得できます。
Virtual DataPort が受け取ったクエリ:
getQuery()
。クエリに含まれるフィールド。つまり、
SELECT
、WHERE
、GROUP BY
、およびHAVING
の句に含まれるフィールドのリスト:getFieldsInQuery()
。クエリを実行するユーザーアカウント:
getCurrentUserName()
。クエリを実行するユーザーアカウントの有効なロールのリスト:
getCurrentUserRoles()
。つまり、そのユーザーに直接付与されているロールと、ユーザー自身のロールではなく、ユーザーのロールに付与されているロール。クエリを実行するコネクションのユーザーエージェント:
getCurrentUserAgent()
。クエリが実行されるデータベース:
getCurrentDatabaseName()
。これはビューが属するデータベースと異なる場合があります。たとえば、データベース「db1」に接続しているときに、SELECT * FROM db2.customer
を実行した場合、このメソッドは「db1」を返します。このカスタムポリシーが割り当てられているユーザーまたはロール:
getPolicyCredentialsName()
およびgetPolicyCredentialsType()
。後者のメソッドは、そのポリシーがユーザーとロールのどちらに割り当てられているかを返します。このカスタムポリシーが割り当てられているビューまたはストアドプロシージャ:
getElementType()
およびgetElementName()
。このカスタムポリシーが割り当てられているエレメントのデータベース:
getElementDatabase()
。クエリのプロパティ。プロパティの値を取得するには
getProperty(...)
を呼び出し、値を変更するにはsetProperty(...)
を呼び出します。使用可能なプロパティは、CustomRestrictionPolicyContext
クラスで定義されている定数 (I18N_PROPERTY
やSWAP_PROPERTY
など) です。JMX を介してデータを取得するためにこのカスタムポリシーで使用できる、Virtual DataPort サーバーへの JMX コネクション:
getJmxConnection()
。Denodo の JMX インターフェイスは、サーバーの現在のステータスに関する情報を提供します。この情報を使用して、Denodo サーバーの負荷や同時クエリ数などに基づいてポリシーの動作を変更できます。メッセージをログに記録するには、
log(...)
メソッドを呼び出します。このメソッドを使用して記録されたメッセージは、ログカテゴリcom.denodo.vdb.catalog.view.CustomRestrictionPolicyContextImpl
にリダイレクトされます。ログカテゴリが有効になっているかどうかの確認:
isLogLevelEnabled(...)
。オプションの完全なリストについては、 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 つ以上のフィールドがクエリに含まれている場合にクエリに条件を追加するには、以下を返します。フィールドが
SELECT
、WHERE
、GROUP BY
、HAVING
の句の少なくとも 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'」がクエリに追加されます。これらのフィールドのどちらもクエリで使用されていない場合、この条件はクエリに追加 されません 。
フィールドのリストに含まれるすべてのフィールドがクエリに含まれている場合にクエリに条件を追加するには、以下を返します。フィールドが
SELECT
、WHERE
、GROUP BY
、HAVING
の句の少なくとも 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 に設定されます。
カスタムポリシーの入力パラメータのいずれかが日時値の場合は、カスタム関数での「 日時型および時間間隔型の処理 」を参照してください。カスタムポリシーの入力パラメータの管理規則は、カスタム関数の場合と同じです。