カスタムビューポリシーの開発¶
カスタムビューポリシーは、アノテーション付きの 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 view 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()
。エレメント
getElementTags()
にタグが割り当てられたコレクション。getFieldsTags()
エレメントからフィールドにタグが割り当てられたマップ。クエリのプロパティ。プロパティの値を取得するには
getProperty(...)
を呼び出し、値を変更するにはsetProperty(...)
を呼び出します。使用可能なプロパティは、CustomRestrictionPolicyContext
クラスで定義されている定数 (I18N_PROPERTY
やSWAP_PROPERTY
など) です。追加の認証情報 (認証メカニズム
getAdditionalAuthenticationInformation()
から提供された場合)。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 に設定されます。
前の例の値を別のマスキングでマスクするには、デフォルトのマスキング式とフィールドごとのマスキング構成があるマップを受け取るコンストラクターを使用します。たとえば、マスク「salary」にはデフォルトの動作が指定されていて、「bonus」には値
0
が指定されているとします。String condition = "1 is null"; Map<String, CustomMaskingExpression> sensitiveFields = new LinkedHashMap<>(); sensitiveFields.put("salary", CustomMaskingExpression.DEFAULT); sensitiveFields.put("bonus", CustomMaskingExpression.SET_0); return new CustomRestrictionPolicyValue(CustomRestrictionPolicyType.ACCEPT_WITH_FILTER, CustomRestrictionPolicyFilterType.MASK_SENSITIVE_FIELDS_IF_ANY_USED, condition, CustomMaskingExpression.REDACT, sensitiveFields);
この例では、「salary」フィールドと「bonus」フィールドの 両方またはどちらか がクエリで使用されている場合、すべての行で、「salary」フィールドには列タイプに応じた
REDACT
式の結果が設定され、「bonus」フィールドは0
に設定されます。オフセット/フェッチ句がある場合でも、ビューから取得する行数を強制的に制限するには、目的の
QUERY_LIMIT
を設定し、ブールFORCE_STRICT_QUERY_LIMIT
を true に設定します。this.context.setProperty("QUERY_LIMIT","50"); this.context.setProperty("FORCE_STRICT_QUERY_LIMIT", String.valueOf(true));
この例では、
QUERY_LIMIT
を 50 に設定し、FORCE_STRICT_QUERY_LIMIT
を true に設定しています。つまり、クエリは最初の 50 個の値を超えたら、それ以上の値を返しません。たとえば、オフセット 10 でクエリを作成し、60 をフェッチした場合、結果に表示されるのは 40 行だけです。
カスタムビューポリシーの入力パラメータのいずれかが日時値の場合は、カスタム関数での「 日時型および時間間隔型の処理 」を参照してください。カスタムビューポリシーの入力パラメータの管理規則は、カスタム関数の場合と同じです。